一、工程模版创建流程
第一步 创建新项目
第二步 选择型号和管脚封装
第三步 RCC使能 外部时钟,高速外部时钟
第四步晶振时钟配置
由数据手册7.1可知外部晶振频率为24MHz 最后一项设置为80
按下回车他会自动配置时钟
第五步,如果不勾选可能程序只会下载一次到时候不好找问题
第6步 名字和路径不能有中文
第七步bsp为创建的程序存放的文件
八创建一个新组
注意程序只能写在USER CODE BEGIN include 和user code end include
9Debug设置 点击确定板载调试器
二、点亮一颗LED灯
原理图
PD2锁存器控制端口
第一步、打开PC8~15的接口配置为output模式
且选中管脚output设置为HIGH,PD2低电平时候为开,防止别的引脚冲突
点击生成即可
第二步 创建两个文件led.c和led.h
定义缩写 在main.h函数内typedef unsigned char uchar
头文件位置要在BEGIN和END之间
第三步、引用头文件配置,这步是点击魔术棒
案例程序----点亮led
main
/----------------------------------main.h-------------------------------/
/* USER CODE BEGIN Includes */
typedef unsigned char uchar;
typedef unsigned int uint;
/* USER CODE END Includes */
/----------------------------------main.h-------------------------------/
头文件
/* USER CODE BEGIN Includes */
#include "led.h"
/* USER CODE END Includes */
主函数
LED_Disp(0x00);//LED初始化
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LED_Disp(0x02);
HAL_Delay(500);
LED_Disp(0x00);
HAL_Delay(1000);
}
/* USER CODE END 3 */
led
/-----------------------------------led.h---------------------------------/
#ifndef __LED_H__
#define __LED_H__
#include "main.h"
void LED_Disp(uchar dsLED);
#endif
/-----------------------------------led.c---------------------------------/
#include "led.h"
void LED_Disp(uchar dsLED)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//先将所有引脚设为高电平由原理图设计
HAL_GPIO_WritePin(GPIOC,dsLED << 8,GPIO_PIN_RESET);//推向高8位
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//锁存器低电平触发
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
三、lcd相关配置及代码案例
LCD原理图
参考和移植官方的案例程序
第一步、引脚配置
全部配置为output
配置完引脚后点击GENERATE CODE即可无需其他操作
第二步、将这两个头文件复制到
在给的案例路径下将lcd.c、fonts、lcd.h也复制到bsp路径下面
第三步、添加头文件
官方案例程序
使用这种格式的颜色背景方便机器阅卷 背景色要求
案例程序----lcd显示
添加lcd
/--------------------------------main.c----------------------------/
头文件
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
/* USER CODE END Includes */
主函数
sprintf函数打印到字符串中
(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),而printf函数打印输出到屏幕上。sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。
3、sprintf函数的格式:
int sprintf( char *buffer, const char *format [, argument,…] );
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
LED_Disp(0x00);//LED初始化
LCD_Init();//LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LED_Disp(0x02);
HAL_Delay(500);
LED_Disp(0x00);
HAL_Delay(1000);
char text[30];
uint i = 5;
sprintf(text," CNBR:%d ",i);
LCD_DisplayStringLine(Line9, (uint8_t *)text);
}
/* USER CODE END 3 */
三、按键配置
按键原理图
第一步、引脚配置
引脚设置为input
第二步 模式设置上下拉模式选择上拉
第三步定时器配置
随便选择一个定时器
时钟选择外部时钟80Mhz---为了达到非阻塞式延时消抖
分屏系数和自动重装载值设置
100HZ=10ms中断一次 从0开始0~79是80个数
计算延时时间实例
中断使能
点击生成代码即可
程序及环境配置
新建两个文件-另存interrupt.c,interrupt.h保存地址为该文件路径下的bsp中
/----------------------------------------------interrupt.h------------------------------------/
interrupt
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include "main.h"
#include "stdbool.h"
struct keys
{
uchar judge_sta;//按键判断
bool key_sta;
bool single_flag;//确认被按下他为1
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
#endif
/----------------------------------------------interrupt.c------------------------------------/
在一个具有多个按键的嵌入式设备按键检测程序中,通过循环遍历 key
数组(改变 i
的值从 0 到数组元素个数减 1),就可以依次获取每个按键的 judge_sta
状态,判断是否满足某些条件来进一步确认按键是否有效按下或者是否进入了特定的操作判断阶段等。
-
case 0
分支:- 逻辑描述:当
key[i].judge_sta
的值为0
时进入该分支。在这个分支里,有一个条件判断语句if(key[i].key_sta == 0)
,也就是当key[i].key_sta
(表示按键当前基本状态,0
在这里可能意味着未按下或者非激活状态等)也为0
时,会将key[i].judge_sta
的值更新为1
。这可能意味着当按键初始处于某个默认的未激活且符合某种前置条件时(由judge_sta
为0
和key_sta
为0
共同界定),将其状态推进到下一个阶段或者设置为另一种待确认的中间状态(用judge_sta
变为1
来表示)。 - 可能的应用场景示例:比如在一个设备启动后,按键初始都处于默认未操作状态,当检测到按键没有被按下(
key_sta
为0
)且其整体判断状态处于初始的0
阶段时,就将其推进到一个准备检测后续是否有按下动作的状态阶段,对应judge_sta
更新为1
。
- 逻辑描述:当
-
case 1
分支:- 逻辑描述:当
key[i].judge_sta
等于1
时执行此分支逻辑。这里的条件判断是if(key[i].key_sta == 0)
,如果key[i].key_sta
为0
(即按键此时处于未按下状态),会执行两个操作:一是将key[i].judge_sta
重置回0
,可能表示此次针对该按键的操作周期结束或者恢复到初始的一种状态等待下次操作;二是将key[i].single_flag
设置为1
,根据之前结构体定义中对single_flag
的注释理解(确认被按下它为1
),这里虽然当前按键是未按下状态,但可能是在满足了之前从judge_sta
为1
阶段的一些检测逻辑后,确认了一次完整的按键操作过程(比如之前从初始状态进入到1
阶段后,又检测到按键松开了,就认为这是一次完整操作),所以设置single_flag
为1
来标记这次操作已完成,可以供程序后续部分依据这个标志做相应处理。 - 可能的应用场景示例:在一个游戏控制按键的处理中,当按下某个按键后
judge_sta
变为1
表示正在检测按下动作,然后松开按键(key_sta
变为0
),此时就可以认为完成了一次有效的按键操作,将judge_sta
回置到0
等待下次操作,同时设置single_flag
为1
通知程序去执行比如游戏角色对应动作等相关功能代码。
- 逻辑描述:当
-
case 2
分支:- 逻辑描述:当
key[i].judge_sta
的值为2
进入该分支。这里的条件判断是if(key[i].key_sta == 1)
,即如果此时按键处于按下状态(key_sta
为1
),会将key[i].judge_sta
的值设置为0
。这或许意味着当按键处于该2
所代表的状态阶段时,如果又检测到它被按下了,那就将其状态重置回初始或者某个默认状态(用judge_sta
变为0
表示),可能是出现了不符合预期的重复按下或者需要重新开始检测该按键的情况等原因。 - 可能的应用场景示例:在一个具有按键组合功能的设备中,如果某个按键单独按下去后进入了
judge_sta
为2
的特定组合检测状态,但随后又检测到它再次被按下不符合当前功能的按键操作逻辑,就将其状态复位到0
以便重新正确地检测后续操作。
- 逻辑描述:当
#include "interrupt.h"
struct keys key[4] = {0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
key[0].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i = 0;i<4;i++)
{
switch (key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta == 0) key[i].judge_sta=1;
}
break;
case 1:
{
if(key[i].key_sta ==0)
{
key[i].judge_sta=0;
key[i].single_flag=1;
}
}
break;
case 2:
{
if(key[i].key_sta==1)
{
key[i].judge_sta=0;
}
}
break;
case 3:
{
}
break;
}
}
}
}
/---------------------------main.c--------------------------------------------/
main
* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"
/* USER CODE BEGIN PTD */
extern struct keys key[];
/* USER CODE END PTD */
/-----------------------------main.c------------------------------------------/
int main(void)
{
/* USER CODE BEGIN 2 */
LED_Disp(0x00);//LED初始化
LCD_Init();//LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim3); //定时器中断
/* USER CODE END 2 */
while (1)
{
char text[30];
uint i = 5;
sprintf(text," CNBR:%d ",i);
LCD_DisplayStringLine(Line9, (uint8_t *)text);
//实现按键的功能
//第一个按键
if(key[0].single_flag==1)
{
sprintf(text," key0down ");
LCD_DisplayStringLine(Line8,(uint8_t *)text);
key[0].single_flag=0;
}
if(key[1].single_flag==1)
{
sprintf(text," key1down ");
LCD_DisplayStringLine(Line8,(uint8_t *)text);
key[1].single_flag=0;
}
}
/* USER CODE END 3 */
}