完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
因为项目原因需要使用stm32l0xx芯片,原本在f103上使用的是标准库开发,改用后发现stm32l0由于比较新,不支持标准库开发,移植很麻烦,只能重新学Hal库开发。
在开发上Hal库还是比较完善的,基本在STM32CubeMX的帮助下可以生成所有所需要的初始化函数,只是需要尽量提前想好需要哪些配置,否则中间再添加main函数内写的代码会被清除。目前把串口收发做好了,查了很多资料,参考了很多博客,因为比较杂一时想不起哪些,无法放全链接,需要可以联系我补上。 (一)USART中断收发(使用的是usart2) Hal库里中断收发主要用到的函数是 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//串口中断发送,以中断方式发送指定长度的数据。 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//串口中断接收,以中断方式接收指定长度数据。 正常情况下开发流程是(一些问题和改进后面会说): (1)初始化USART 直接调用 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); 这段代码由MX直接生成,不需要改动什么。 在USART_Init中 if(Hal_UART_Init(&huart2) ==OK) 这是使能了USART2以及配置一些硬件设备 (2)中断处理函数 在初始化后,进行中断处理函数,在stm32l0xx_it.c中找到 void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ /* USER CODE END USART2_IRQn 0 */ HAL_UART_IRQHandler(&huart2); /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ } 这些都是生成好的,其中 HAL_UART_IRQHandler(&huart2);是Hal库处理UART中断请求,这个函数是一个总的中断处理函数,也就是很多串口的中断处理最后都汇集到这个地方来处理go to definition,会发现其内是一系列包括清中断、读取寄存器等操作,我们也不需要管,但也不能删掉。 void USART2_IRQHandler(void)作为中断处理函数是每次中断触发都会运行的,所以如果有什么自己写的中断服务函数,可以在这里面添加。 (3)回调函数 回调函数我是写在main.c里的 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-》Instance==USART2)//判断,如果是串口2 { //写入自己要实现的代码 } } 每次中断后会进入这段函数,go to definition一下会发现 __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ UNUSED(huart); /* NOTE: This function should not be modified, when the callback is needed, the HAL_UART_RxHalfCpltCallback can be implemented in the user file. */ } 出现在stn32l0xx_hal_uart.c里,这里__weak表示可以在用户文件中实现,实现后只会调用用户文件里的函数。 我在这个函数里调用了HAL_UART_Transmit();这样就能打印出接收的数据。 (4)使能中断 中断使能是在初始化后添加HAL_UART_Receive_IT(); 实际使用 __HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE); 也可以实现。 在这之后,中断收发基本都都好了,整个过程除了添加收发数组,使能函数和回调函数,基本不用做什么改动。 这里要记得 HAL_UART_IRQHandler(&huart2);后还要再用HAL_UART_Receive_IT();使能中断,不然只能收一次。 最后代码是这样的: main.c stm32l0xx_it.c 然后编译执行时会发现,发送不满100不打印,发送超过100只打印前100(这里的100是由于我使能的时候填的100)。 后面我考虑可能是因为只有到设定的数据量后才触发回调函数,然后我把HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);的Size改为了1 然后就是这样子了,对,它坏了。 于是开始翻各种博客,最后找到了通过直接对寄存器操作实现不限字数中断收发,顺便实现了printf重定向。 代码实现如下: 添加接收状态标记: uint16_t USART2_RX_STA=0; 在usart2初始化函数里添加中断使能 __HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE); 在中断处理函数中添加寄存器状态读取部分 void USART2_IRQHandler(void) //串口2中断服务程序 { uint8_t Res; HAL_UART_IRQHandler(&huart2); if(__HAL_UART_GET_IT(&huart2, UART_IT_RXNE) != RESET) //产生中断 { USART2-》RQR |= 0x08; Res =USART2-》RDR;//USARTx_RX_Data(&UartHandle); if((USART2_RX_STA&0x8000)==0)// { if(USART2_RX_STA&0x4000)// { if(Res!=0x0a) USART2_RX_STA=0;// else USART2_RX_STA|=0x8000; // } else { if(Res==0x0d) USART2_RX_STA|=0x4000; else { USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ; USART2_RX_STA++; if(USART2_RX_STA》(USART_REC_LEN-1)) USART2_RX_STA=0; } } } } HAL_NVIC_ClearPendingIRQ(USART2_IRQn); } 当有数据时产生中断,标记位为1,数据存入USART2_RX_BUF。 在主函数while(1)里添加 if(USART2_RX_STA&0x8000)//接收到数据 { //写入自己要实现的代码 USART2_RX_STA = 0; } 发送时需要发送数据长度,可以由下面操作得到 len=USART2_RX_STA&0x3f; 另附上printf重定向部分 #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 void _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART2-》ISR&0X40)==0) { };//循环发送,直到发送完毕 USART2-》TDR = (uint8_t) ch; return ch; } #endif 实现效果如下: 由衷感谢提供了帮助的博主。 (二)USART DMA IDLE收发 在实现上面中断收发后,就想把usart1用DMA来实现收发,与之前一样DMA用到的函数是 HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//串口DMA发送,以DMA方式发送指定长度的数据。 HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);//串口DMA接收,以DMA方式接收指定长度的数据 与中断一样串口发送很简单,其他的不多说,这里注意一个就是DMA发送需要打开串口的中断并使能,即 否则只能发送一次,不能再发送。 直接使用DMA接收与中断接收基本类似,会有类似的数据长度固定的问题,下面直接给出解决方案: 定义接收标志 volatile uint8_t RX_flag=0; //IDLE 接收标志 在初始化函数里使能中断和DMA HAL_UART_Receive_DMA(&huart1, usartDMA_rxBuf, RECEIVELEN); /*使能DMA接收*/ __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); /*使能串口空闲中断*/ 在中断处理函数添加寄存器读取部分 void USART1_IRQHandler(void) { UsartReceive_IDLE(&huart1); HAL_UART_IRQHandler(&huart1); } void UsartReceive_IDLE(UART_HandleTypeDef *huart) { uint32_t temp; if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); HAL_UART_DMAStop(&huart1); temp = huart1.hdmarx-》Instance-》CNDTR; rx_len = RECEIVELEN - temp; HAL_UART_Receive_DMA(&huart1,usartDMA_rxBuf,RECEIVELEN); RX_flag=1; } } 在主函数while(1)里添加 if(RX_flag == 1) { //写入自己要实现的代码 rx_len = 0; RX_flag = 0; } 这里需要注意的就是DMA接收需要配置为循环模式,DMA发送配置为普通模式 实现效果如下 以上为开发过程中自己的理解以及参考别的博客实现的串口功能,存在不足与误导感谢批评指正,有问题也可以留言讨论。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1632 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1559 浏览 1 评论
985 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1605 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
652浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
521浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 09:21 , Processed in 0.882407 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号