使用STM32的过程中,最常用到的就是串口了。我们经常可以通过串口来打印一下内部变量的值,通过打印来看目前程序的运行状态等,最常用到的还是串口1,尤其是串口1的printf函数,完全兼容C语言的printf,使用起来非常的方便。但是当我们使用的外设较多时,并且好几个外设都需要使用串口进行通信时,只是用串口1,就不足以完成项目的需求。本文主要介绍如何同时使用STM32的三个串口。主要包括
1.如何同时打开串口1 2 3,并且互不干扰。
2.如何通过已打开的串口2 3实现类似于串口1的printf函数的功能。
3.如何连续输出一个十六进制字符数组。
4.如何实现通过串口直接获取一个格式化类型值,比如直接获取一个int值。
本文的测试程序运行在STM32F103C8T6上,采用库函数版本,如果需要移植,请参考博主另一篇文章https://mp.csdn.net/postedit/102093845。
1.时钟
在使用任何外设的时候都需要先知道外设对应的时钟,先将外设的时钟打开,我们先打开Datasheet看一下系统的架构图。从图上可以看出串口1挂载在APB2上,而串口2和串口3挂载在APB1上。打开时钟的操作就是调用库函数即可,例如对于串口1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
即可打开串口1时钟
打开串口1 时钟之后,只是打开了串口1的功能,我们还需要打开串口1用来与外界通信的管脚的时钟,也就是IO口的时钟,每一个串口对应的TX和RX管脚在Datasheet中也可以找到,如下所示为串口1的TXD和RXD,从中可看出TXD为PA9,RXD为PA10。我们需要打开GPIOA的时钟,上图中可以看出GPIOB时钟挂在载在APB2上。因此
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
即可打开时钟。相应的串口2和串口3的对应管脚在数据手册中也可以找到,相应的如下。
串口2:TXD->PA2 RXD->PA3
串口3:TXD->PB10 RXD->PB11
2.管脚的配置
由于对于TXD需要发送数据,因此需要上拉提高输出能力,同时端口的功能为复用功能,因此TXD需要设置成复用上拉模式。
对于RXD需要接收数据,设置成浮空输入即可。串口1的端口初始化如下:
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用上拉输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIOA.9
//USART1_RX GPIOA.10³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIOA.10
3.串口的配置
串口主要包括波特率,数据位,停止位,校验位的长度,NVIC优先级以及中断等设置。串口1初始化函数如下所示
//Usart1 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC
//USART 初始化
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位1未
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口1
串口2初始化函数如下所示
void uart_init2(u32 bound){
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
//USART2_RX GPIOA.3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 初始化
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQÍ初始化通道使能
NVIC_Init(&NVIC_InitStructure); //NVIC初始化
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
}
串口3初始化如下:
void uart_init3(u32 bound){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_Cmd(USART3, ENABLE);
}
4.中断函数
在上述过程中,我们打开了串口的接受使能,因此需要定义相应的中断响应函数,响应函数中我们每次接受一个字符(这也是我们设置好的,8位数据位,也就是一个字节的数据),同时将数据进行保存,同时在中断函数中要清除中断标志位。
上述是我们必须做的,目前一些开发板的厂商在中断函数中加入了一些特殊的含义,比如每次检测到换行符(即\r\n)作为一个字符串的结束,也就是每一次必须发送以换行符为结尾的字符串,才被识别为一个字符串。我们必须知道这并不是必须的,程序是自己写的,我们可以接受5个字符串作为一次接受,也可以以aa为结尾这都是可以的。一个最简单的串口接受函数如下:
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //进入接受中断
{
Res =USART_ReceiveData(USART1);//读取寄存器中的值
}
}
实际中我们可以自己定制,为了方便,本次也采用接受换行符作为结束,相应的串口1的中断函数为
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接受中断
{
Res =USART_ReceiveData(USART1);
if((USART_RX_STA&0x8000)==0)//接受没有完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d 即\r
{
if(Res!=0x0a)USART_RX_STA=0;//接收到了\r 但是下一个不是\n那么重新接受
else USART_RX_STA|=0x8000; //接受到了\n 那么接受结束
}
else //没有接收到\r
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;//将数据存到USART_RX_BUF这个数组中
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接受的数据超过了预定的长度,重新接受
}
}
}
}
}
从上面的程序可以看出,最终\r\n之前的字符串都被保存到了 USART_RX_BUF这个数组中,数组的长度为USART_REC_LEN。
整个usart.c文件的内容如下
#include "sys.h"
#include "usart.h"
#if SYSTEM_SUPPORT_OS
#include "includes.h"
#endif
#if 1
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
_sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //Èç¹ûʹÄÜÁ˽ÓÊÕ
//´®¿Ú1ÖжϷþÎñ³ÌÐò
//×¢Òâ,¶ÁÈ¡USARTx->SRÄܱÜÃâĪÃûÆäÃîµÄ´íÎó
char USART_RX_BUF[USART_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.
//½ÓÊÕ״̬
//bit15£¬ ½ÓÊÕÍê³É±êÖ¾
//bit14£¬ ½ÓÊÕµ½0x0d
//bit13~0£¬ ½ÓÊÕµ½µÄÓÐЧ×Ö½ÚÊýÄ¿
u16 USART_RX_STA=0; //½ÓÊÕ״̬±ê¼Ç
void uart_init(u32 bound){
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜUSART1£¬GPIOAʱÖÓ
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
//USART1_RX GPIOA.10³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.10
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//ÇÀÕ¼ÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
//USART ³õʼ»¯ÉèÖÃ
USART_InitStructure.USART_BaudRate = bound;//´®¿Ú²¨ÌØÂÊ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæÅ¼Ð£Ñéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
USART_Init(USART1, &USART_InitStructure); //³õʼ»¯´®¿Ú1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
USART_Cmd(USART1, ENABLE); //ʹÄÜ´®¿Ú1
}
void USART1_IRQHandler(void) //´®¿Ú1ÖжϷþÎñ³ÌÐò
{
u8 Res;
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
{
Res =USART_ReceiveData(USART1); //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý
if((USART_RX_STA&0x8000)==0)//½ÓÊÕδÍê³É
{
if(USART_RX_STA&0x4000)//½ÓÊÕµ½ÁË0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//½ÓÊÕ´íÎó,ÖØÐ¿ªÊ¼
else USART_RX_STA|=0x8000; //½ÓÊÕÍê³ÉÁË
}
else //»¹Ã»ÊÕµ½0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//½ÓÊÕÊý¾Ý´íÎó,ÖØÐ¿ªÊ¼½ÓÊÕ
}
}
}
}
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntExit();
#endif
}
#endif
#if EN_USART2_RX //Èç¹ûʹÄÜÁ˽ÓÊÕ
//´®¿Ú1ÖжϷþÎñ³ÌÐò
//×¢Òâ,¶ÁÈ¡USARTx->SRÄܱÜÃâĪÃûÆäÃîµÄ´íÎó
u8 USART2_RX_BUF[USART2_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.
//½ÓÊÕ״̬
//bit15£¬ ½ÓÊÕÍê³É±êÖ¾
//bit14£¬ ½ÓÊÕµ½0x0d
//bit13~0£¬ ½ÓÊÕµ½µÄÓÐЧ×Ö½ÚÊýÄ¿
u16 USART2_RX_STA=0; //½ÓÊÕ״̬±ê¼Ç
void uart_init2(u32 bound){
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜUSART1£¬GPIOAʱÖÓ
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
//USART1_RX GPIOA.10³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.10
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//ÇÀÕ¼ÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
//USART ³õʼ»¯ÉèÖÃ
USART_InitStructure.USART_BaudRate = bound;//´®¿Ú²¨ÌØÂÊ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæÅ¼Ð£Ñéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
USART_Init(USART2, &USART_InitStructure); //³õʼ»¯´®¿Ú1
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
USART_Cmd(USART2, ENABLE); //ʹÄÜ´®¿Ú1
}
void USART2_IRQHandler(void) //´®¿Ú1ÖжϷþÎñ³ÌÐò
{
u8 Res;
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
{
Res =USART_ReceiveData(USART2); //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý
if((USART2_RX_STA&0x8000)==0)//½ÓÊÕδÍê³É
{
if(USART2_RX_STA&0x4000)//½ÓÊÕµ½ÁË0x0d
{
if(Res!=0x0a)USART2_RX_STA=0;//½ÓÊÕ´íÎó,ÖØÐ¿ªÊ¼
else USART2_RX_STA|=0x8000; //½ÓÊÕÍê³ÉÁË
}
else //»¹Ã»ÊÕµ½0X0D
{
if(Res==0x0d)USART2_RX_STA|=0x4000;
else
{
USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
USART2_RX_STA++;
if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//½ÓÊÕÊý¾Ý´íÎó,ÖØÐ¿ªÊ¼½ÓÊÕ
}
}
}
}
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntExit();
#endif
}
#endif
#if EN_USART3_RX //Èç¹ûʹÄÜÁ˽ÓÊÕ
//´®¿Ú1ÖжϷþÎñ³ÌÐò
//×¢Òâ,¶ÁÈ¡USARTx->SRÄܱÜÃâĪÃûÆäÃîµÄ´íÎó
u8 USART3_RX_BUF[USART3_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.
//½ÓÊÕ״̬
//bit15£¬ ½ÓÊÕÍê³É±êÖ¾
//bit14£¬ ½ÓÊÕµ½0x0d
//bit13~0£¬ ½ÓÊÕµ½µÄÓÐЧ×Ö½ÚÊýÄ¿
u16 USART3_RX_STA=0; //½ÓÊÕ״̬±ê¼Ç
void uart_init3(u32 bound){
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //ʹÄÜUSART1£¬GPIOAʱÖÓ
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//USART1_TX GPIOB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
//USART1_RX GPIOB.11³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIOA.10
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//ÇÀÕ¼ÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
//USART ³õʼ»¯ÉèÖÃ
USART_InitStructure.USART_BaudRate = bound;//´®¿Ú²¨ÌØÂÊ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæÅ¼Ð£Ñéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
USART_Init(USART3, &USART_InitStructure); //³õʼ»¯´®¿Ú1
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
USART_Cmd(USART3, ENABLE); //ʹÄÜ´®¿Ú1
}
void USART3_IRQHandler(void) //´®¿Ú1ÖжϷþÎñ³ÌÐò
{
u8 Res;
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
{
Res =USART_ReceiveData(USART3); //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý
if((USART3_RX_STA&0x8000)==0)//½ÓÊÕδÍê³É
{
if(USART3_RX_STA&0x4000)//½ÓÊÕµ½ÁË0x0d
{
if(Res!=0x0a)USART3_RX_STA=0;//½ÓÊÕ´íÎó,ÖØÐ¿ªÊ¼
else USART3_RX_STA|=0x8000; //½ÓÊÕÍê³ÉÁË
}
else //»¹Ã»ÊÕµ½0X0D
{
if(Res==0x0d)USART3_RX_STA|=0x4000;
else
{
USART3_RX_BUF[USART3_RX_STA&0X3FFF]=Res ;
USART3_RX_STA++;
if(USART3_RX_STA>(USART3_REC_LEN-1))USART3_RX_STA=0;//½ÓÊÕÊý¾Ý´íÎó,ÖØÐ¿ªÊ¼½ÓÊÕ
}
}
}
}
#if SYSTEM_SUPPORT_OS //Èç¹ûSYSTEM_SUPPORT_OSÎªÕæ£¬ÔòÐèÒªÖ§³ÖOS.
OSIntExit();
#endif
}
#endif
usart.h文件的内容如下
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN 200 //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý 200
#define EN_USART1_RX 1 //ʹÄÜ£¨1£©/½ûÖ¹£¨0£©´®¿Ú1½ÓÊÕ
#define USART2_REC_LEN 200 //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý 200
#define EN_USART2_RX 1 //ʹÄÜ£¨1£©/½ûÖ¹£¨0£©´®¿Ú1½ÓÊÕ
#define USART3_REC_LEN 200 //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý 200 USART3_REC_LEN
#define EN_USART3_RX 1 //ʹÄÜ£¨1£©/½ûÖ¹£¨0£©´®¿Ú1½ÓÊÕ
extern u8 USART3_RX_BUF[USART3_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.Ä©×Ö½ÚΪ»»Ðзû
extern u16 USART3_RX_STA; //½ÓÊÕ״̬±ê¼Ç
extern u8 USART2_RX_BUF[USART2_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.Ä©×Ö½ÚΪ»»Ðзû
extern u16 USART2_RX_STA; //½ÓÊÕ״̬±ê¼Ç
extern char USART_RX_BUF[USART_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.Ä©×Ö½ÚΪ»»Ðзû
extern u16 USART_RX_STA; //½ÓÊÕ״̬±ê¼Ç
//Èç¹ûÏë´®¿ÚÖжϽÓÊÕ£¬Ç벻ҪעÊÍÒÔϺ궨Òå
void uart_init(u32 bound);
void uart_init2(u32 bound);
void uart_init3(u32 bound);
#endif
5.程序调用
现在串口的函数基本完成,可以在主程序中进行调用,首先我们需要先调用三个串口初始化函数,之后进行发送数据。
//串口波特率均为9600
uart_init(9600);
uart_init2(9600);
uart_init3(9600);
此时在main()函数中通过printf()函数已经可以进行字符串的输出,比如
a='1';
printf("a=%c\r\n",a);
此时串口1即可输出
a=1
1.串口接收数据
前面在中断函数中,我们接收一次完成之后,都进行了
USART_RX_STA|=0x8000;
的操作,那么每次接受到一个换行符之后USART_RX_STA的首位都应该是1,那么我们只需要在程序中进行查询该位即可。如果为1 那么一次接受完成,我们可以从 USART_RX_BUF中读出本次接受的数据,同时USART_RX_STA在每接收到一个字符之后都将加一,那么USART_RX_STA中存的就是数据的长度,当然我们需要先将首位数据换回0,而数据长度最多我们设置的200,那么将USART_RX_STA与0x3fff(或者0x7fff 首位为0 且小于200的数据均可以)按位相与即可获得长度。接受函数如0下
if(USART_RX_STA&0x8000){
len=USART_RX_STA&0x3fff;
printf("Serial1 Receive:\r\n%s\r\n",USART_RX_BUF);
USART_RX_STA=0;
for(i=0;i<len;i++) USART_RX_BUF[i]=0;
}
如果每次就收数据的长度是可变的,那么最后一个for循环是必须的。否则数据将会出错。比如第一次接受12345,第二次如果接收到678的话,如果没有最后一行,那么USART_RX_BUF数组中存的为67845,程序将会出错。
2.串口2和3格式化输出
串口2和串口3的输出函数需要自己进行定义,内容如下。
//串口2 发送字符串函数
void printf2(char* sendData){
u8 t=0;
while(sendData[t]!='\0'){
USART2->DR=sendData[t];
while((USART2->SR&0X40)==0);//等待发送完完成
t++;
}
}
//串口3 发送字符串
void printf3(char* sendData){
u8 t=0;
while(sendData[t]!='\0'){
USART3->DR=sendData[t];
while((USART3->SR&0X40)==0);//等待发送完成
t++;
}
}
此时main()函数中可以通过调用如下代码完成字符串的输出。
printf2("hello world!\r\n");
printf3("I am AlwaysSun\r\n");
那么如何实现像串口1类似的格式化字符串输出呢?博主一般的做法是采用C语言的sprintf()函数。sprinft()函数的介绍如下
int sprintf( char *buffer, const char *format, [ argument] … );
这个函数包含三个部分的参数:
buffer:char型指针,指向将要写入的字符串的缓冲区。
format:格式化字符串。即可选参数的想要输入的数据类型。
[argument]…:可选参数,可以是任何类型的数据。
简单来说这个函数就是将format格式的字符串,输出到buffer指针指向的地方。这么说有点不好懂,我们用代码举例子
int age=10;
char outString[30]={""};
sprintf(outString,"I am %d years old\r\n",age);
那么字符串outString中保存的内容就是 I am 10 years old\r\n
那么串口2和3实现串口1的功能,方法为
char a='1';
char outString[20]={""};
sprintf(outString,"a=%c\r\n",a);
printf2(outString);
3.串口格式化输入
有时候我们需要获取一个int值,但是串口接受的是字符串类型的数据,如果对字符串进行手动分割之后进行转化,那么将十分的复杂,此时我们可以通过另一个厉害的函数sscanf(),这个函数的用法和sprintf()大致相似,这里不进行介绍。通过串口输入int类型的值例子如下
int getNum=0;
sscanf(USART_RX_BUF,"s-%d-e",&getNum);//UASRT_RX_BUF数组中存放的是串口接收到的数据 s-248-e
printf("getNum=%d\r\n",getNum);
那么将会输出getNum=248。有没有很方便,如果是其他的类型的话,使用方法类似。
4.串口连续输出十六进制数组
有时候我们需要通过十六进制数组成通信协议,如果使用printf这种函数进行发送,那么十分复杂,而采用USART_SendData(USART1,0x01);
搭配for循环这种方法,串口将只能得到最后一个数据,那么如何发送多个十六进制数而不被覆盖呢?我们分析一下,为啥胡数据被覆盖呢,原因只可能是前一个数据还没有发完,或者还是在等待发送的状态,后一个数据就进入到了发送缓冲区,将前一个数据覆盖掉了,那么我们只需要在发送下一个数据的时候,等待前一个数据发送完毕即可。博主一般采用等待发送中断的方法,如下:
void UartA1SendStr(u8 *pucStr,u8 Num)
{
u8 i;
for(i = 0;i<Num;i++)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,*pucStr++);
}
}
这样就可以实现十六进制数组的发送。
本程序整体实现上述功能main()函数代码如下:
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
char usartReceive2[50]={""};
char usartReceive3[50]={""};
u8 voice_welcome[10]={0x7e,0xff,0x06,0x16,0x00,0x00,0x00,0xfe,0xe5,0xef};
int getNum=0;
//´®¿Ú2 ·¢ËÍ×Ö·û´®
void printf2(char* sendData){
u8 t=0;
while(sendData[t]!='\0'){
USART2->DR=sendData[t];
while((USART2->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø
t++;
}
}
//´®¿Ú3·¢ËÍ×Ö·û´®
void printf3(char* sendData){
u8 t=0;
while(sendData[t]!='\0'){
USART3->DR=sendData[t];
while((USART3->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø
t++;
}
}
//´®¿Ú1 ·¢ËÍÊ®Áù½øÖÆ×Ö·û´®
void UartA1SendStr(u8 *pucStr,u8 Num)
{
u8 i;
for(i = 0;i<Num;i++)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,*pucStr++);
}
}
//´®¿Ú2 ·¢ËÍÊ®Áù½øÖÆ×Ö·û´®
void UartA2SendStr(u8 *pucStr,u8 Num)
{
u8 i;
for(i = 0;i<Num;i++)
{
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
USART_SendData(USART2,*pucStr++);
}
}
//´®¿Ú3 ·¢ËÍÊ®Áù½øÖÆ×Ö·û´®
void UartA3SendStr(u8 *pucStr,u8 Num)
{
u8 i;
for(i = 0;i<Num;i++)
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);
USART_SendData(USART3,*pucStr++);
}
}
int main(void)
{
u8 i;
u8 len,len2,len3;
SystemInit();
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
uart_init(9600); //´®¿Ú³õʼ»¯Îª9600
uart_init2(9600); //´®¿Ú³õʼ»¯Îª9600
uart_init3(9600); //´®¿Ú³õʼ»¯Îª9600
LED_Init(); //³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
while(1)
{
LED0=!LED0;
//´®¿Ú·¢ËÍ×Ö·û´®
printf("Hello Everyone.I Am Serial1\r\n");
printf2("Hello Everyone.I Am Serial2\r\n");
printf3("Hello Everyone.I Am Serial3\r\n");
//´®¿Ú·¢ËÍÊ®Áù½øÖÆ×Ö·ûÊý×é
/*UartA1SendStr(voice_welcome,10);
UartA2SendStr(voice_welcome,10);
UartA3SendStr(voice_welcome,10);*/
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È 0011
printf("Serial1 Receive:\r\n%s\r\n",USART_RX_BUF);
sscanf(USART_RX_BUF,"s-%d-e",&getNum);
printf("getNum=%d\r\n",getNum);
USART_RX_STA=0;
for(i=0;i<len;i++) USART_RX_BUF[i]=0;
}
if(USART2_RX_STA&0x8000)
{
len2=USART2_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È
sprintf(usartReceive2,"Serial2 Receive:\r\n%s\r\n",USART2_RX_BUF);//USART2_RX_BUF
printf2(usartReceive2);
USART2_RX_STA=0;
for(i=0;i<len2;i++) USART2_RX_BUF[i]=0;
}
if(USART3_RX_STA&0x8000)
{
len3=USART3_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È
sprintf(usartReceive3,"Serial3 Receive:\r\n%s\r\n",USART3_RX_BUF);
printf3(usartReceive3);
USART3_RX_STA=0;
for(i=0;i<len3;i++) USART3_RX_BUF[i]=0;
}
delay_ms(1500);
}
}
项目下载地址https://download.csdn.net/download/qq_34020487/11962625