你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32L051开始添加需要的代码经验分享

[复制链接]
攻城狮Melo 发布时间:2023-6-12 19:18
1、LED灯的闪烁

在主函数while循环中直接使用延时控制:

  1. HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  2.     HAL_Delay(1000);
复制代码

测试正常,这个延时1S钟靠肉眼识别,如果有误差其实也看不出来,影响delay应该是和系统时钟有关,后续再确定是否正常;


2、定时器控制LED闪烁

在tim.c文件中对应处添加  HAL_TIM_PeriodElapsedCallback 函数,这是定时器中断的响应函数,当然,参数的定义(这里使用的参数只不过是以前使用F103保留下来直接复制过来的,我这里就没有进行对应的处理),相关.h文件的包含不要忘记添加。还有一个需要注意的,定时器初始化了,需要在主函数中开启定时器所以进行以下操作,LED会每隔3S切换一次

  1. /* USER CODE BEGIN 2 */
  2.   HAL_TIM_Base_Start_IT(&htim2);
  3.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 1 */
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  3. {
  4.   if(htim->Instance==TIM2){
  5.     Timer3_count++;
  6.     if(Timer3_count >= 3){
  7.       Timer3_count = 0;
  8.       HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);   
  9.     }
  10.       
  11.   }
  12.   else if(htim->Instance==TIM21){
  13.     ++Timer4_count;
  14.   if(Timer4_count>0X1FFFFFF)Timer4_count=0;   
  15.   }
  16. }
  17. /* USER CODE END 1 */
复制代码

3、串口相关3.1 printf函数的实现
  1. /* USER CODE BEGIN 0 */
  2. #if 1
  3. #include <stdio.h>

  4. /* 告知连接器不从C库链接使用半主机的函数 */
  5. #pragma import(__use_no_semihosting)

  6. /* 定义 _sys_exit() 以避免使用半主机模式 */
  7. void _sys_exit(int x)
  8. {
  9.     x = x;
  10. }

  11. /* 标准库需要的支持类型 */
  12. struct __FILE
  13. {
  14.     int handle;
  15. };

  16. FILE __stdout;

  17. int fputc(int ch, FILE *stream)
  18. {
  19.     /* 堵塞判断串口是否发送完成 */
  20.     while((USART1->ISR & 0X40) == 0);

  21.     /* 串口发送完成,将该字符发送 */
  22.     USART1->TDR = (uint8_t) ch;

  23.     return ch;
  24. }
  25. #endif
  26. /* USER CODE END 0 */
复制代码


其中需要说明的是,如果是F103 ,不是 ISR 和 TDR 寄存器,而是 SR  DR寄存器


3.2 串口接收不定长度的数据

在 usart.c 文件中添加  HAL_UART_RxCpltCallback  函数,对应的缓存数组不要忘记定义,我们这里使用的是 LPUART1 和 我的无线通讯模块通讯(以前F103对应的引脚是串口3),在中断响应函数中把串口接收到的数据存到 USART_Enocean_BUF 中,然后在主函数中实现打印接收到的一串数据。

  1. /* USER CODE BEGIN 1 */
  2. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  3. {
  4.   if(huart->Instance == LPUART1){
  5.     Enocean_Data++;
  6.     HAL_UART_Receive_IT(&hlpuart1, (uint8_t *)&USART_Enocean_BUF[Enocean_Data], 1);
  7.   }
  8.   else if(huart->Instance==USART1)
  9.   {
  10.       // HAL_UART_Transmit_IT(&huart1,(uint8_t *)USART1_BUF, 10);
  11.       // HAL_UART_Receive_IT(&huart1, (uint8_t *)USART1_BUF, 10);  
  12.   }
  13. }
  14. /* USER CODE END 1 */
复制代码
  1.   /* Infinite loop */
  2.   /* USER CODE BEGIN WHILE */
  3.   while (1)
  4.   {
  5.     if(test_data != Enocean_Data){
  6.         HAL_Delay(7);
  7.         HAL_UART_Transmit(&huart1,USART_Enocean_BUF, Enocean_Data,0xFFFF);     //将串口3接收到的数据通过串口1传出   
  8.         memset(USART_Enocean_BUF, 0, sizeof(USART_Enocean_BUF));   //清空缓存区
  9.         Enocean_Data=0;
  10.         (&hlpuart1)->pRxBuffPtr = &USART_Enocean_BUF[Enocean_Data];//这一句很重要,没有这一句,后面接收会出错
  11.     }
  12.     /* USER CODE END WHILE */

  13.     /* USER CODE BEGIN 3 */
  14.   }
  15.   /* USER CODE END 3 */
复制代码

和定时器一样要注意,串口开启中断接收,需要在初始化后执行一次中断接收的函数 HAL_UART_Receive_IT ,类似于开启中断接收:

  1.   /* USER CODE BEGIN 2 */
  2.   HAL_TIM_Base_Start_IT(&htim2);
  3.   //使能串口中断接收
  4.   HAL_UART_Receive_IT(&hlpuart1, (uint8_t *)&USART_Enocean_BUF[0], 1);
  5.   /* USER CODE END 2 */
复制代码

完成了以上操作,就能够实现将LPUART1 收到的数据,通过串口1打印出来

今天还发现一个细节,HAL_UART_RxCpltCallback 函数不需要再次在.h文件中申明,因为HAL库中虽然是 _weak 声明的,但是在底层stm32L0xx_hal_uart.h中已经申明了,所以在应用程序中申不申明都可以


4、独立看门狗

看门狗还是比较简单的,直接在循环中加一个喂狗函数就可以:

  1. HAL_IWDG_Refresh(&hiwdg);
  2.   }
  3.   /* USER CODE END 3 */
复制代码

这里我也测试了下上一篇文章我设置的看门狗时间,当时计算出来看门狗时间为6.4S,是准确的。


5、按键驱动移植

因为自己以前用到了一个非常好用的按钮设计,所以一直保留至今,直接上.c 和 .h文件

  1. /*
  2. 2019/5/21 按键程序移植成功,以后可以使用此按键,需要研究一下
  3. 和以前单片机项目按钮方式类似  
  4. by  qzh
  5. 2019/8/30  
  6. 确定了第三行,第一个必须是7,才能按下到时间自动触发
  7. by  qzh
  8. */
  9. #include "mod_button.h"


  10. //GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
  11. void io_getDigital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value)
  12. {
  13. *pu8Value = HAL_GPIO_ReadPin(GPIOx,GPIO_Pin);
  14. }

  15. void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount)  
  16. {
  17. // __HAL_TIM_SET_COUNTER
  18. HAL_TIM_Base_Start_IT(&htim21);
  19. // HAL_TIM_Base_Stop_IT
  20. // TIM_Cmd(TIM4, ENABLE);
  21. if(pu8timer->on == 0)
  22.   pu8timer->on = 1;
  23. if(pu8timer->on == 1)
  24.   //IntNum = 0;
  25.   pu8timer->timeInit = Timer4_count;
  26. //pu8timer->timeInit = IntNum;
  27. pu8timer->timeOut = 0;
  28. pu8timer->timeToCount = u32timeToCount;
  29. }

  30. RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer)
  31. {
  32. uint32 Temp_Val;
  33. if(Timer4_count > pu8timer->timeInit)
  34.   Temp_Val = Timer4_count - pu8timer->timeInit;
  35. else
  36.   Temp_Val = (0xFFFFFFFF-pu8timer->timeInit)+Timer4_count;
  37. if(Temp_Val >= pu8timer->timeToCount)
  38. {
  39.   pu8timer->timeOut = 1;
  40.   pu8timer->on = 0;
  41.   pu8timer->timeToCount = 0;
  42.   pu8timer->timeInit = 0;
  43. }
  44. else
  45.   pu8timer->timeOut = 0;
  46. return (pu8timer->timeOut == 1)?TIME_OUT:OK;
  47. }

  48. BTN_STATE btn_getState(BTN_STRUCT *pBtn)
  49. {
  50. const uint8 transition_table[8][4]={ 0, 1, 0, 1,
  51.           5, 2, 5, 1,
  52.           7, 2, 5, 3,
  53.           5, 4, 5, 4,
  54.           5, 4, 5, 4,
  55.           6, 1, 0, 1,
  56.           6, 1, 7, 1,
  57.           0, 1, 0, 1 };

  58. //register uint8 u8Input;
  59. uint8 u8Input;
  60. // Get button state
  61. io_getDigital(pBtn->u8Pin,pBtn->GPIO_Pin ,&u8Input);
  62. u8Input = (u8Input == pBtn->u8ActiveState)?1:0;

  63. // Get timeout state
  64. u8Input |= ((time_getTimeOut(&(pBtn->tTimer))==TIME_OUT)?2:0);

  65. // Get new state
  66. pBtn->u8State = transition_table[pBtn->u8State][u8Input]; // we want only the state, not action

  67. // Perform action
  68. switch (pBtn->u8State)
  69. {
  70.   case 1:
  71.    time_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutON);
  72.    break;
  73.   case 5:
  74.    time_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutOFF);
  75.    break;
  76. }
  77. // return pBtn->u8State;
  78. //待测试
  79. return (BTN_STATE)pBtn->u8State;
  80. }


  81. void Button_Action()
  82. {
  83. /*
  84. 按键动作,模式选择
  85. */
  86. }
复制代码
  1. #ifndef _MOD_BUTTON_H_INCLUDED
  2. #define _MOD_BUTTON_H_INCLUDED

  3. #include "main.h"
  4. #include "Datadef.h"
  5. #include "tim.h"
  6. /*
  7.        Timeout ON
  8.                 _______|_____
  9. P             |             |    Timeout OFF
  10. R  ___________|             |________|____
  11.   ^      ^  ^    ^  ^  ^   ^    ^
  12. S  0    1  2    3  4  5  6    7

  13. P - pressed, R - released, S - BTN_STATE
  14. */

  15. /*
  16. °´Å¥Ïà¹Ø  KEY1  learn  PB5  KEY2  CLEAR  PB6
  17. */
  18. #define BTN_ACTIVE    0       //when pressed, switch to GND


  19. typedef struct
  20. {
  21. // Public
  22. //uint8  u8Pin;   // e.g. ADIO0
  23. //uint16  u8Pin;   // e.g. ADIO0
  24. GPIO_TypeDef * u8Pin;
  25. uint16_t    GPIO_Pin;
  26. uint8  u8ActiveState; // button is pressed if (io_getDigital(u8Button)==bActiveState)
  27. uint16  u16TimeOutON; // time the button has to be pressed to be recognized as pressed
  28. uint16  u16TimeOutOFF; // time the button has to be pressed to be recognized as released

  29. // Private
  30. TIMER_TYPE tTimer;
  31.   uint8  u8State;

  32. } BTN_STRUCT;

  33. typedef enum
  34. {
  35. BTN_IDLE = 0,
  36. BTN_EDGE1,
  37. BTN_TRIGGERED,
  38. BTN_PRESSED, //< most important
  39. BTN_PRESS_HOLD,
  40. BTN_EDGE2,
  41. BTN_RELEASE_HOLD,
  42. BTN_RELEASED
  43. } BTN_STATE;

  44. extern u16 Timer4_count;

  45. BTN_STATE btn_getState(BTN_STRUCT *pBtn);
  46. void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount);
  47. void io_getDigital(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value);
  48. RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer);


  49. #endif //_MOD_BUTTON_H_INCLUDED
复制代码

在主函数中添加需要用到的按钮操作:

  1. /* USER CODE BEGIN 3 */
  2.     if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){
  3.         HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  4.     }

  5.     if((btn_getState(&K1_BUTTON_2S)==BTN_PRESSED)){
  6.        while(btn_getState(&K1_BUTTON_150mS));
  7.     }

  8.     if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){
  9.         HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  10.         HAL_Delay(150);
  11.         HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  12.     }
  13.     HAL_IWDG_Refresh(&hiwdg);
  14.   }
  15.   /* USER CODE END 3 */
复制代码

测试结果OK。


6、软件复位
  1. /* Private user code ---------------------------------------------------------*/
  2. /* USER CODE BEGIN 0 */
  3. void SoftReset(void)
  4. {
  5.     __set_FAULTMASK(1); // 关闭所有中断
  6.     NVIC_SystemReset(); // 复位
  7. }
  8. /* USER CODE END 0 */
复制代码


其实上面这个是有问题的,在HAL库中没有__set_FAULTMASK(1)这个,直接如下:

  1. /* USER CODE BEGIN 0 */
  2. void SoftReset(void)
  3. {
  4.     HAL_NVIC_SystemReset(); // 复位
  5. }
  6. /* USER CODE END 0 */
复制代码

或者直接用HAL_NVIC_SystemReset();这个函数在程序中就可以;

小结,基本上项目上使用到的串口,LED,按钮等功能都测试过了,然后我还得把通讯模块的底层一些驱动移植过来,其实也就是根据通讯模块的串口协议进行的一系列操作。这里就不说明,等今天完成这部分,下一篇文章会来写一下通过IO口,软件模拟的I2C接口测试。


转载自: 矜辰所致

如有侵权请联系删除


收藏 评论0 发布时间:2023-6-12 19:18

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版