学习前言:
嵌入式学习的基础就是STM32开发板各个模块的熟练使用,已经对应功能的实现
HAL库由于Cubemx的开发带来了巨大便利,所以熟练掌握该开发软件的使用很重要,其实也就是对时钟的配置以及各个引脚的功能实现
另外多读代码提供编程能力必不可少
整体开发板的所有应用及组合如图:
第一个程序(cubemx的使用)
①cubemx中选择芯片型号
②使能必要IO口【晶振与下载接口】:RCC_OSC_IN and RCC_OSC_OUT(External crystal oscillator)、SWDIO and SWCLK(CMSIS DAP Link)
③配置时钟Clock Configuration【重要】:外部时钟设置为24MHz,第一个选择器选择HSI即内部RC振荡器(没用HSE是因为引脚与LED冲突),PLLM为2分频,PLL内部先乘20再除以2,最终得80MHz,第二个选择器选择PLLCLK,后APB1和APB2总线时钟均设置为80MHz(此设置根据官方学习程序配置)
④在Project Manager中,确定工程名称、位置、IDE,勾选为每个外设初始化生成c和h文件。GENERATE CODE生成工程
/*****细节注意
⑤在keil中,打开Options for Target(魔术棒),Output勾选Create HEX File,Debug菜单右上角选择CMSIS-DAP Debugger,进入Setting,Port选择SW,Max Clock选择10MHz,如果插上开发板(注意板子有两个接口,插上DOWNLOAD接口),在SW Device中可以看到芯片IDCODE和Name,进入Flash Download选择Erase Full Chip,Reset and Run,然后下方Add添加Flash编程算法,选择STM32G4X,128K,确定保存
***/
LED模块-
创建新工程,使能PD2(信号锁存引脚,点亮灯的操作需要先对灯操作,然后依次拉高、拉低PD2引脚)拉低,使能PC8-PC15对应LED1-LED8,低电平亮,高电平灭
代码-【对GPIO高低电平的设置,只需使用WritePin(GPIOX,GPIO_PIN_x,GPIO_PIN_STATION)函数来直接操作对应端口】:
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); //拉高PD2,将PC信号送入输入端
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);//拉低PD2,锁存输出端信号
HAL_Delay(1000);
注:操作LED时需要设置全部的LED状态,因为对LCD操作也会影响LED状态
按键和定时器中断模块
传统按键检测有两种方式,一种直接读IO电平状态,另一种是中断,这两种方式都处理按键抖动都有些许误差,因此使用定时器来计数判断按键是否按下
创建新工程,使用timer1,时钟源选择 内部时钟【Internal Clock】,分频系数选择80,意味着一个tick是1us,计数值设为9999,则定时器中断周期为10ms,在NVIC Settings中使能更新中断
代码中需要在主循环上方手动启动定时器中断:HAL_TIM_Base_Start_IT(&htim1);
在timer.c文件最后加上回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == (&htim1))
{
static uint8_t keycount = 0; //按键计数
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
{
keycount ++;
}else keycount = 0;
if(keycount == 8)
{ //这个值根据情况设定,if内为key按下执行的内容
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
keycount = 0; //计数清零
a++;
}
}
}
// 长、短按
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == (&htim1))
{
static int keycount = 0,key2count = 0; //按键计数 keycount是判断有按键按下, key2count是判断长或短按
if(keycount >= 8)
{ //这个值根据情况设定 消抖
key2count++;
if(key2count>=100)
{ //长按
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET); }
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET)
{ //短按
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
}
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
{
keycount ++;
}else {
keycount = 0;key2count=0;
}
}
}
/*****这里对回调函数做个补充,该函数是最常用于我们编程逻辑的实现*******/
回调函数是一种编程技术,可以在事件发生时执行预定义的代码。在STM32中,回调函数通常是在硬件发生特定事件时调用的,例如定时器中断、串口接收中断、外部中断等。回调函数的作用是可以在事件发生时执行一些需要及时响应的操作,例如读取传感器数据、处理接收到的数据、控制外设等。
回调函数的使用通常是通过HAL库实现的,HAL库提供了一些预定义的回调函数和函数指针,可以方便地在需要时进行调用。在使用HAL库时,通常需要先进行相关的初始化和配置,然后注册相应的回调函数。当事件发生时,HAL库会自动调用相应的回调函数进行处理。
例如,当使用定时器时,需要先初始化定时器、设置时钟源和预分频等参数,然后注册一个回调函数用于处理定时器中断事件。当定时器中断事件发生时,HAL库会自动调用该回调函数执行预定义的代码。在回调函数中可以进行各种操作,例如修改输出状态、读取传感器数据等。
回调函数的使用可以提高程序的响应速度和实时性,特别是在实时控制和数据采集应用中,回调函数经常被使用。需要注意的是,回调函数需要占用一定的资源和时间,因此在设计时需要合理选择回调函数的数量和复杂度,以避免影响程序的性能。
一种最简单的方法可以说直接读取IO电平状态判断按键是否按下:
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
HAL_Delay(100);
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14 | GPIO_PIN_15);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
}