完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
串口发送数据
1、串口发送数据最直接的方式就是标准调用库函数 。 void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 1 第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展: void Send_data(u8 *s) { while(*s!=‘ ’) { while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET); USART_SendData(USART1,*s); s++; } } 123456789 以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。 while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET); 1 这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下: void Send_data(USART_TypeDef * USARTx,u8 *s) { while(*s!=‘ ’) { while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET); USART_SendData(USARTx,*s); s++; } } 123456789 这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。 当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下: void USART_printf ( USART_TypeDef * USARTx, char * Data, 。.. ) { const char *s; int d; char buf[16]; va_list ap; va_start(ap, Data); while ( * Data != 0 ) // 判断是否到达字符串结束符 { if ( * Data == 0x5c ) //‘’ { switch ( *++Data ) { case ‘r’: //回车符 USART_SendData(USARTx, 0x0d); Data ++; break; case ‘n’: //换行符 USART_SendData(USARTx, 0x0a); Data ++; break; default: Data ++; break; } } else if ( * Data == ‘%’) { // switch ( *++Data ) { case ‘s’: //字符串 s = va_arg(ap, const char *); for ( ; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; case ‘d’: //十进制 d = va_arg(ap, int); itoa(d, buf, 10); for (s = buf; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; default: Data++; break; } } else USART_SendData(USARTx, *Data++); while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET ); } } 该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。 |
|
|
|
直接使用printf函数。
很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数; 如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用: |
|
|
|
串口接受数据
串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。 这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。 #define Max_BUFF_Len 18 unsigned char Uart2_Buffer[Max_BUFF_Len]; unsigned int Uart2_Rx=0; void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); //接收串口1数据到buff缓冲区 Uart2_Rx++; if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len) //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收) { if(Uart2_Buffer[0] == ‘+’) //检测到头标识是我们需要的 { printf(“%srn”,Uart2_Buffer); //这里我做打印数据处理 Uart2_Rx=0; } else { Uart2_Rx=0; //不是我们需要的数据或者达到最大接收数则开始重新接收 } } } } 1234567891011121314151617181920212223242526 数据的头标识为“n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。 这样做的有以下好处: 1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改 2.可以接受指定的数据 3.防止接收的数据使数组越界 这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。 以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。 所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。 #define DMA_USART1_RECEIVE_LEN 18 void USART1_IRQHandler(void) { u32 temp = 0; uint16_t i = 0; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { USART1-》SR; USART1-》DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志 DMA_Cmd(DMA1_Channel5,DISABLE); temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 for (i = 0;i 《 temp;i++) { Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i]; } //设置传输数据长度 DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN); //打开DMA DMA_Cmd(DMA1_Channel5,ENABLE); } } 1234567891011121314151617181920212223 之前的串口中断是一个一个字符的接收,现在改为串口空闲中断,就是一帧数据过来才中断进入一次。而且接收的数据时候是DMA来搬运到我们指定的缓冲区(也就是程序中的USART1_RECEIVE_DMABuffer数组),是不占用CPU时间资源的。 最后在讲下DMA的发送: #define DMA_USART1_SEND_LEN 64 void DMA_SEND_EN(void) { DMA_Cmd(DMA1_Channel4, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel4,DMA_USART1_SEND_LEN); DMA_Cmd(DMA1_Channel4, ENABLE); |
|
|
|
只有小组成员才能发言,加入小组>>
801 浏览 1 评论
999 浏览 1 评论
12433 浏览 0 评论
5885 浏览 3 评论
17675 浏览 6 评论
996浏览 1评论
971浏览 1评论
806浏览 1评论
3852浏览 1评论
1003浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 16:05 , Processed in 0.996266 second(s), Total 84, Slave 66 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号