基础任务-驱动LED灯

一.目标选择 1.启动CubeMX->ACCESS TO MCU SELECTOR 进入目标选择界面,
2.选择芯片型号,双击启动芯片配置
二.基本配置 选择时钟源 System Core->RCC,
HIGH Speed Clock(HSE)->BYPASS Clock Source旁路模式 配置调试接口 System
Core->SYS Debug-> Serial Wire SWD串行调试接口 引脚分配 单击PA5->GPIO_Output 默认引脚名称将变为亮绿色。
三.外设配置 SystemCore->GPIO
单击PA5初始电平,引脚模式,上下拉电阻,引脚速度,引脚名称修改提高可读性
四.时钟配置
1.修改时钟源频率
2.选择锁相环输入时钟
3.选择系统时钟源
4.设置HCLK频率,并且回车
五.工程配置 工程名称 保存路径 使用的IDE
完成以上,生成工程。
六.程序编写
在main.c文件中添加用户代码,位置在USER CODE BEGIN3 和USER CODE END3 之间 MA_GPIO_Init()
程序编译,程序下载,工程设置里,在Debug标签也中选择仿真器,并勾选Reset and Run 同时可利用Debug图标进入程序调试界面。

进阶任务-按键控制

任务内容:采用查询方式检测按键状态,按键按下后执行操作,翻转LD2状态。
前沿抖动5-10ms,后沿抖动:5-10ms :外接低通RC滤波消抖,或者软件消抖:
1.检测出按键闭合后执行延时程序,延时时间为5-10ms,用于去掉前沿抖动
2.再次检测按键状态,如果保持闭合状态,才认为按下,并执行相应的按键任务。
3.按键的释放可以采用延时或者循环检测的方式去掉后沿抖动。
引脚分配,外设配置
,死循环程序不予采用。应采用状态奇和定时器中断结合去抖动。

状态机

状态机是一个抽象概念,表示把一个过程抽象为若干个状态之间的切换,这些状态之间存在一点的联系,状态机的设计主要包括4个要素:
1.现态:指当前所处的状态。
2.条件:当一个条件满足,将会触发一个动作,或者执行一次状态的迁移。
3.动作:
表示条件满足后执行动作,动作执行完毕后,可以迁移到新的状态,也可以保持原状态。动作要素不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新的状态。
4.次态:表示条件满足后要迁往的新状态。

按键的状态机实现

一、状态定义:根据按键的波形图可以设计三个按键状态
1.按键检测状态(无按键按下状态)2.按键确认状态(按键已经按下状态)3.按键释放状态(等待按键释放状态)
二、状态转换条件(假设低表示按下)
1.当处于按键监测状态时,若数据线为低,则转换到按键确认状态,否则保持当前状态。
2.当处于按键确认状态是,若数据线为低,则转换到按键释放状态,并设置按键有效标志,如果数据线为高,则表示可能有干扰信号,转换到按键检测状态
3.当处于按键释放状态是,若数据线位高,这转换到按键检测状态,表示完成了本次按键检测,否则保持当前状态。
三、编程实现 利用Switch,case多分支语句,通过检测按键引脚的电平来实现按键状态的转换
利用定时器产生10ms的定时中断,在中断服务程序中调用按键状态转换函数,每次执行间隔10ms,可有效消除按键抖动,并提高CPU的利用率。
CubeMX外设配置
TIMERS->TIM10,activated NVIC,enable
定义枚举类型三个按键状态数据类型
typedef enum{KEY_CHECK = 0, KEY_CONFIRM.KEY_RELEASE}KEY_STATE; 程序添加在USER CODE BEGIN PTD与USER CODE END PIT之间
定义变量
KEY_STATE KeyState = KEY_CHECK;//按键状态,初值位按键检测状态。
uint8_t KeyFlag = 0;//按键有效标志,1:有效,0:无效 程序添加在USER CODE BEGIN PV 与USER CODE END PV之间。
主程序代码:
/*USER CODE BEGIN 2 */
HAL TIM Base Start_IT(&htim10);// 使能定时器10更新中断,启动定时器10
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//后台程序,检测相关标志位,执行相应操作
if( KeyFlag == 1)//检测按键有效标志
{
KeyFlag = 0;// 清除标志
HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin); // 按键执行任务: 翻转LD2
}
} /* USER CODE END 3 */
// 定时器定时中断的回调函数,相当于中断服务程序
/*USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ if(htim->Instance == TIM10) // 判断更新中断来源
switch(KeyState)
{
case KEY_CHECK: //按键检测状态
{
// 读到低电平,进入按键确认状态
if(HAL_GPIO_ReadPin(B1 GPIO Port,B1 Pin) == GPIOPIN RESET)
{
KeyState = KEY_COMFIRM;
}
break;
}
case KEY_COMFIRM: //按键确认状态
{
// 读到低电平,进入按键释放状态
if(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin) == GPIO_PINRESET)
{
KeyState = KEY_RELEASE;// 设置有效按键标志,表示按键按下后立即执行按键任务
KeyFlag = 1;
}
//读到高电平,可能是干扰信号,返回初始状态: 按键检测状态
else
{
KeyState = KEY_CHECK;
}
break;
}
case KEY_RELEASE: //按键释放状态
{ // 读到高电平,说明按键释放,返回初始状态: 按键检测状态
// 读到高电平,说明按键释放,返回初始状态: 按键检测状态,结束本次按键过程。
// 读到低电平,说明按键没有释放,保持当前状态
if(HAL_GPIO_ReadPin(B1_GPIO_Port,Bl_Pin) == GPIO_PIN_SET)
{
KeyState = KEY_CHECK;
// KeyFlag = 1; // 设置有效按键标志,表示按键释放后执行按键任务
}
break;
}
default: break;
}
}
/ *USER CODE END 4*/

数据类型及函数声明添加位置及函数命名规则

头文件,数据类型及函数声明的添加位置
用户头文件: Private includes---/*USER CODE BEGIN Includes*/ /*USER CODE END Includess*/
用户自定义数据类型: Private typedef ---/*USER CODE BEGIN PTD*/ /*USER CODE END PTD*/
用户常量定义: Private define ---/*USER CODE BEGIN PD*/ /*USER CODE END PD*/
用户宏函数定义: Private macro ---/*USER CODE BEGIN PM*/ /*USER CODE END PM*/
用户变量定义: Private variables---/*USER CODE BEGIN PV*/ /*USER CODE END PV*/
用户函数声明: Private function prototypes/*USER CODE BEGIN PFP *//*USER CODE END PFP */
用户代码添加位置
后台程序: 在while循环中USER CODE BEGIN 3和USER CODE END3
外设启动: USER CODE BEGIN 2 和USER CODE END 2
用户函数和中断回调函数:USER CODE BEGIN 4和USER CODE END 4
变量及函数的命名规则
1.见名知意:利用英文单词或者其缩写形式定义变量或函数,名称要体现变量的作用或函数的功能,切记不要使用拼音来命名
2.变量一般采用名词形式命名,多个单词间利用大小写字母作为间隔。全局变量的首字母大写,如KeyFlag; 局部变量的首字母小写,如keyFlag,便于区分全局变量和局部变量。
3.函数一般采用动宾结构命名,首字母大写,也是利用大小写字母作为间隔,如GetValue等
4.宏定义和用户自定义数据类型全部采用大写字母,利用下划线作为间隔,如KEY_STATE等