既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
void USART\_SendData(USART_TypeDef\* USARTx, uint16_t Data);
第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展:
void Send\_data(u8 \*s)
{
while(\*s!='\0')
{
while(USART\_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
USART\_SendData(USART1,\*s);
s++;
}
}
以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。
while(USART\_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下:
void Send\_data(USART_TypeDef \* USARTx,u8 \*s)
{
while(\*s!='\0')
{
while(USART\_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET);
USART\_SendData(USARTx,\*s);
s++;
}
}
这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如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的函数写法加以补充。
2、 直接使用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("%s\r\n",Uart2_Buffer); //这里我做打印数据处理
Uart2_Rx=0;
}
else
{
Uart2_Rx=0; //不是我们需要的数据或者达到最大接收数则开始重新接收
}
}
}
}
数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。
这样做的有以下好处:
1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改
2.可以接受指定的数据
3.防止接收的数据使数组越界
这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。
以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!