1、LED灯的闪烁 在主函数while循环中直接使用延时控制: - HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- HAL_Delay(1000);
复制代码
测试正常,这个延时1S钟靠肉眼识别,如果有误差其实也看不出来,影响delay应该是和系统时钟有关,后续再确定是否正常;
2、定时器控制LED闪烁在tim.c文件中对应处添加 HAL_TIM_PeriodElapsedCallback 函数,这是定时器中断的响应函数,当然,参数的定义(这里使用的参数只不过是以前使用F103保留下来直接复制过来的,我这里就没有进行对应的处理),相关.h文件的包含不要忘记添加。还有一个需要注意的,定时器初始化了,需要在主函数中开启定时器所以进行以下操作,LED会每隔3S切换一次 - /* USER CODE BEGIN 2 */
- HAL_TIM_Base_Start_IT(&htim2);
- /* USER CODE END 2 */
复制代码- /* USER CODE BEGIN 1 */
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance==TIM2){
- Timer3_count++;
- if(Timer3_count >= 3){
- Timer3_count = 0;
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- }
-
- }
- else if(htim->Instance==TIM21){
- ++Timer4_count;
- if(Timer4_count>0X1FFFFFF)Timer4_count=0;
- }
- }
- /* USER CODE END 1 */
复制代码
3、串口相关3.1 printf函数的实现
- /* USER CODE BEGIN 0 */
- #if 1
- #include <stdio.h>
- /* 告知连接器不从C库链接使用半主机的函数 */
- #pragma import(__use_no_semihosting)
- /* 定义 _sys_exit() 以避免使用半主机模式 */
- void _sys_exit(int x)
- {
- x = x;
- }
- /* 标准库需要的支持类型 */
- struct __FILE
- {
- int handle;
- };
- FILE __stdout;
- int fputc(int ch, FILE *stream)
- {
- /* 堵塞判断串口是否发送完成 */
- while((USART1->ISR & 0X40) == 0);
- /* 串口发送完成,将该字符发送 */
- USART1->TDR = (uint8_t) ch;
- return ch;
- }
- #endif
- /* USER CODE END 0 */
复制代码
其中需要说明的是,如果是F103 ,不是 ISR 和 TDR 寄存器,而是 SR DR寄存器
3.2 串口接收不定长度的数据在 usart.c 文件中添加 HAL_UART_RxCpltCallback 函数,对应的缓存数组不要忘记定义,我们这里使用的是 LPUART1 和 我的无线通讯模块通讯(以前F103对应的引脚是串口3),在中断响应函数中把串口接收到的数据存到 USART_Enocean_BUF 中,然后在主函数中实现打印接收到的一串数据。 - /* USER CODE BEGIN 1 */
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if(huart->Instance == LPUART1){
- Enocean_Data++;
- HAL_UART_Receive_IT(&hlpuart1, (uint8_t *)&USART_Enocean_BUF[Enocean_Data], 1);
- }
- else if(huart->Instance==USART1)
- {
- // HAL_UART_Transmit_IT(&huart1,(uint8_t *)USART1_BUF, 10);
- // HAL_UART_Receive_IT(&huart1, (uint8_t *)USART1_BUF, 10);
- }
- }
- /* USER CODE END 1 */
复制代码- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- if(test_data != Enocean_Data){
- HAL_Delay(7);
- HAL_UART_Transmit(&huart1,USART_Enocean_BUF, Enocean_Data,0xFFFF); //将串口3接收到的数据通过串口1传出
- memset(USART_Enocean_BUF, 0, sizeof(USART_Enocean_BUF)); //清空缓存区
- Enocean_Data=0;
- (&hlpuart1)->pRxBuffPtr = &USART_Enocean_BUF[Enocean_Data];//这一句很重要,没有这一句,后面接收会出错
- }
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
复制代码
和定时器一样要注意,串口开启中断接收,需要在初始化后执行一次中断接收的函数 HAL_UART_Receive_IT ,类似于开启中断接收: - /* USER CODE BEGIN 2 */
- HAL_TIM_Base_Start_IT(&htim2);
- //使能串口中断接收
- HAL_UART_Receive_IT(&hlpuart1, (uint8_t *)&USART_Enocean_BUF[0], 1);
- /* USER CODE END 2 */
复制代码
完成了以上操作,就能够实现将LPUART1 收到的数据,通过串口1打印出来 今天还发现一个细节,HAL_UART_RxCpltCallback 函数不需要再次在.h文件中申明,因为HAL库中虽然是 _weak 声明的,但是在底层stm32L0xx_hal_uart.h中已经申明了,所以在应用程序中申不申明都可以
4、独立看门狗看门狗还是比较简单的,直接在循环中加一个喂狗函数就可以: - HAL_IWDG_Refresh(&hiwdg);
- }
- /* USER CODE END 3 */
复制代码
这里我也测试了下上一篇文章我设置的看门狗时间,当时计算出来看门狗时间为6.4S,是准确的。
5、按键驱动移植因为自己以前用到了一个非常好用的按钮设计,所以一直保留至今,直接上.c 和 .h文件 - /*
- 2019/5/21 按键程序移植成功,以后可以使用此按键,需要研究一下
- 和以前单片机项目按钮方式类似
- by qzh
- 2019/8/30
- 确定了第三行,第一个必须是7,才能按下到时间自动触发
- by qzh
- */
- #include "mod_button.h"
- //GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
- void io_getDigital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value)
- {
- *pu8Value = HAL_GPIO_ReadPin(GPIOx,GPIO_Pin);
- }
- void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount)
- {
- // __HAL_TIM_SET_COUNTER
- HAL_TIM_Base_Start_IT(&htim21);
- // HAL_TIM_Base_Stop_IT
- // TIM_Cmd(TIM4, ENABLE);
- if(pu8timer->on == 0)
- pu8timer->on = 1;
- if(pu8timer->on == 1)
- //IntNum = 0;
- pu8timer->timeInit = Timer4_count;
- //pu8timer->timeInit = IntNum;
- pu8timer->timeOut = 0;
- pu8timer->timeToCount = u32timeToCount;
- }
- RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer)
- {
- uint32 Temp_Val;
- if(Timer4_count > pu8timer->timeInit)
- Temp_Val = Timer4_count - pu8timer->timeInit;
- else
- Temp_Val = (0xFFFFFFFF-pu8timer->timeInit)+Timer4_count;
- if(Temp_Val >= pu8timer->timeToCount)
- {
- pu8timer->timeOut = 1;
- pu8timer->on = 0;
- pu8timer->timeToCount = 0;
- pu8timer->timeInit = 0;
- }
- else
- pu8timer->timeOut = 0;
- return (pu8timer->timeOut == 1)?TIME_OUT:OK;
- }
- BTN_STATE btn_getState(BTN_STRUCT *pBtn)
- {
- const uint8 transition_table[8][4]={ 0, 1, 0, 1,
- 5, 2, 5, 1,
- 7, 2, 5, 3,
- 5, 4, 5, 4,
- 5, 4, 5, 4,
- 6, 1, 0, 1,
- 6, 1, 7, 1,
- 0, 1, 0, 1 };
-
- //register uint8 u8Input;
- uint8 u8Input;
- // Get button state
- io_getDigital(pBtn->u8Pin,pBtn->GPIO_Pin ,&u8Input);
- u8Input = (u8Input == pBtn->u8ActiveState)?1:0;
-
- // Get timeout state
- u8Input |= ((time_getTimeOut(&(pBtn->tTimer))==TIME_OUT)?2:0);
- // Get new state
- pBtn->u8State = transition_table[pBtn->u8State][u8Input]; // we want only the state, not action
- // Perform action
- switch (pBtn->u8State)
- {
- case 1:
- time_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutON);
- break;
- case 5:
- time_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutOFF);
- break;
- }
- // return pBtn->u8State;
- //待测试
- return (BTN_STATE)pBtn->u8State;
- }
- void Button_Action()
- {
- /*
- 按键动作,模式选择
- */
- }
复制代码- #ifndef _MOD_BUTTON_H_INCLUDED
- #define _MOD_BUTTON_H_INCLUDED
- #include "main.h"
- #include "Datadef.h"
- #include "tim.h"
- /*
- Timeout ON
- _______|_____
- P | | Timeout OFF
- R ___________| |________|____
- ^ ^ ^ ^ ^ ^ ^ ^
- S 0 1 2 3 4 5 6 7
- P - pressed, R - released, S - BTN_STATE
- */
- /*
- °´Å¥Ïà¹Ø KEY1 learn PB5 KEY2 CLEAR PB6
- */
- #define BTN_ACTIVE 0 //when pressed, switch to GND
- typedef struct
- {
- // Public
- //uint8 u8Pin; // e.g. ADIO0
- //uint16 u8Pin; // e.g. ADIO0
- GPIO_TypeDef * u8Pin;
- uint16_t GPIO_Pin;
- uint8 u8ActiveState; // button is pressed if (io_getDigital(u8Button)==bActiveState)
- uint16 u16TimeOutON; // time the button has to be pressed to be recognized as pressed
- uint16 u16TimeOutOFF; // time the button has to be pressed to be recognized as released
-
- // Private
- TIMER_TYPE tTimer;
- uint8 u8State;
- } BTN_STRUCT;
- typedef enum
- {
- BTN_IDLE = 0,
- BTN_EDGE1,
- BTN_TRIGGERED,
- BTN_PRESSED, //< most important
- BTN_PRESS_HOLD,
- BTN_EDGE2,
- BTN_RELEASE_HOLD,
- BTN_RELEASED
- } BTN_STATE;
- extern u16 Timer4_count;
- BTN_STATE btn_getState(BTN_STRUCT *pBtn);
- void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount);
- void io_getDigital(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value);
- RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer);
- #endif //_MOD_BUTTON_H_INCLUDED
复制代码
在主函数中添加需要用到的按钮操作: - /* USER CODE BEGIN 3 */
- if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- }
- if((btn_getState(&K1_BUTTON_2S)==BTN_PRESSED)){
- while(btn_getState(&K1_BUTTON_150mS));
- }
- if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- HAL_Delay(150);
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- }
- HAL_IWDG_Refresh(&hiwdg);
- }
- /* USER CODE END 3 */
复制代码
测试结果OK。
6、软件复位
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- void SoftReset(void)
- {
- __set_FAULTMASK(1); // 关闭所有中断
- NVIC_SystemReset(); // 复位
- }
- /* USER CODE END 0 */
复制代码
其实上面这个是有问题的,在HAL库中没有__set_FAULTMASK(1)这个,直接如下: - /* USER CODE BEGIN 0 */
- void SoftReset(void)
- {
- HAL_NVIC_SystemReset(); // 复位
- }
- /* USER CODE END 0 */
复制代码
或者直接用HAL_NVIC_SystemReset();这个函数在程序中就可以; 小结,基本上项目上使用到的串口,LED,按钮等功能都测试过了,然后我还得把通讯模块的底层一些驱动移植过来,其实也就是根据通讯模块的串口协议进行的一系列操作。这里就不说明,等今天完成这部分,下一篇文章会来写一下通过IO口,软件模拟的I2C接口测试。
转载自: 矜辰所致 如有侵权请联系删除
|