关于上次的串口内容只是知道怎么用,不晓得什么意思,这次就做个笔记详细的来描述一下。关于STM32有许多通信的协议,其中串口也是常用的通信协议,并且串口用来调试和查看信息非常重要的。包括用到阿里云的云智能,ESP8266的通信,总之许多信息的调优和调试都可以用这个来打印并且观测,目的就是为了查看信息用的多。
STM32的开发板许多个,这个就要看自己使用哪一个系列的开发板对应的串口数量也不一样。
下面就直接分析代码吧。
首先就是串口对应的引脚需要定义结构体以及串口的结构体。同时开启对应的时钟
void Uart_Init(void)
{
USART_InitTypeDef Uart_Initsturte; //定义UART结构体
GPIO_InitTypeDef GPIO_Initsture; // 定义传输的引脚
NVIC_InitTypeDef NVIC_INitstrute; //串口使用中断
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启UART3 PB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //开始UART时钟
这里分别对应的波特率:就是串口通信之间的速度,只有在两个通信之间拥有同样的波特率才可以无差别传输,波特率不相同传输的数据就会产生误差。无硬件流控制,就是利用软件触发控制、同时需要用到电脑发送和单片机接收,所以定义收发模式。校验位就是数据的校验位,分别由奇检验和偶检验,这里用到的是无检验,奇检验就是当传输的位是双的时候,这个检验位就会在后面添加一个0让这个数据位变成奇数,偶检验同理。停止位1位就是数据收完后的结束位。数据长度8位也就是接收的数据位是8位的。
Uart_Initsturte.USART_BaudRate=115200;//波特率
Uart_Initsturte.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无硬控制流
Uart_Initsturte.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //收发模式
Uart_Initsturte.USART_Parity=USART_Parity_No ; // 无校验位
Uart_Initsturte.USART_StopBits= USART_StopBits_1 ; //停止位
Uart_Initsturte.USART_WordLength=USART_WordLength_8b ; //数据长度位
USART_Init(USART1,&Uart_Initsturte); //结构体写入寄存器
USART_StructInit(&Uart_Initsturte);
这里定义的是串口的引脚,分别引脚上面对应的RX和TX这里同时也需要对两个引脚定义的模式也是不一样的,当是发送的引脚TX也就是PA9的时候需要定义的是推挽输出,因为数据的发送就是由这个引脚来完成的。那么PA10就是数据接收的引脚了,这个引脚就要用到模拟输入的模式了。
//复用推挽
GPIO_Initsture.GPIO_Pin=GPIO_Pin_9;
GPIO_Initsture.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Initsture.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,& GPIO_Initsture);
GPIO_Initsture.GPIO_Pin=GPIO_Pin_10;
GPIO_Initsture.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入,因为是要从电脑写到单片机
GPIO_Init(GPIOA,& GPIO_Initsture);
这里的代码与上面的是连接对应的,分别是给串口上电,然后上电后清楚一下串口的标志位,最后开启串口的中断标志位,这样才能表示是否可以接收数据,那么串口接收发送数据它也是一个事件,那么在单片机中,事件是需要开启中断的,因为只有这样才可以分清楚单片机在运行的时候,具体执行那个程序,这样也可以防止单片机的事件混淆,同时也不会太占用运行机制。
USART_Cmd(USART1,ENABLE); //开启串口
USART_ClearFlag(USART1,USART_FLAG_TC); //清除标志位
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启接收中断标志位
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组
NVIC_INitstrute.NVIC_IRQChannel= USART1_IRQn ; //打开UART1的中断
NVIC_INitstrute.NVIC_IRQChannelCmd=ENABLE;
NVIC_INitstrute.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级
NVIC_INitstrute.NVIC_IRQChannelSubPriority=1; //响应优先级
NVIC_Init(&NVIC_INitstrute);
}
那么最后我们定义完了,就要用到单片机发送数据的函数了,这个函数在库里面是定义的,我们只需要调用来用就好了。当我们需要发送字符的时候就可以利用这个来发送字符了,但是只能发送一个字符。
//利用函数发送字符电脑
void USART_Senbyte(USART_TypeDef* USARTx,uint16_t data)
{
while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET); //如果发送标志位没有在发送的时候
USART_SendData(USARTx,data);
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
}
所以我们需要利用C语言的知识来定义发送字符串,当我们的字符串写完的时候,我们知道它是有一个结束符合\0的,所以我们只有判断这个就好了。
//利用函数发送字符串电脑
void USART_SenStr(USART_TypeDef* USARTx,char *str)
{
while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET); //如果发送标志位没有在发送的时候
while(*str!='\0')
{
USART_SendData(USART1,*str);
str++;
}
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
}
我们字符可以发送出去了,但是我们接收呢,上面说到接收标志位中断事件,所以我们要用这个串口的中断函数。每一个串口对应着一个中断函数。所以我们调用,然后利用接收的函数USART_ReceiveData,以及接收的标志位状态,当我们的接收状态没有在的时候,我们就可以接收字符了,接收字符我们可以定义一个数组用来接收收到的字符,同时接收完字符后,就要清除这个标志位状态,这样我们才是一个接收完整的流程。
//判断接收回来的字符串
void USART1_IRQHandler (void)
{
static unsigned char i=0;
if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
{
Recive_table[i]=USART_ReceiveData(USART1); //MCU接收wifi模块反馈回来的数据
i++;
if(Recive_table[i-1]=='\n')
{
Recive_table[i]='\0';
i=0; //遇到换行 重新装值
Recive_state = 1;
}
}
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}