一.STM32F103有两个串口
图中 TXD/RXD
是相对
CH340G
来说的,也就是
USB
串口的发送和接收引脚。而 USART1_RX 和
USART1_TX
则是相对于
STM32F103ZET6
来说的。也就是说2和4内部连接的是RS232的USB口。
意思很简单,就是说你要用USB串口将程序烧写到STM32中或者是要通过USB串口将电脑和STM32串口通信的时候,就需要用跳线帽将1、2和3、4短接。如果你想要其他外设和STM32串口通信的时候,就是拔掉1、2和3、4上面的跳线帽,将外设的TX和PA10连接,RX和PA9连接。
外面的USB串口的CH340的接收发送内部连接的是单片机的2、4,所以用到USB的时候,就需要插上跳线帽了。
图中,USART2_RX
和
USART2_TX
分别连接在
STM32F103ZET6
的
PA3
和
PA2
上面,
RS485_TX
和
RS485_RX
则分别连接在
SP3485
的
RO
和
DI
引脚。当我们用
2
个跳线帽短接
P5
的
1
和
3
、
2
和
4
,即可实现
RS485
接口连接在
STM32
的串口
2
上面,完成
RS485
通信。当拔
了这两个跳线帽的时候,该接口可以实现
2
个功能:
1
,作为
PA2
和
PA3
的引出
IO
口;
2
,开
发板的
RS485
部分,作为
RS485
转
TTL
模块使用。
具体意思就是:插上跳线帽,进行的是RS485通信。
RS485通信原理图及程序实例详解_wise18146705004的博客-CSDN博客_rs485通信原理
拔掉跳线帽,RS485
转
TTL
模块使用,PA2和PA3作为单独的串口使用。
二.串口的使用
1.使用串口的基本步骤
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
}
对以上代码的解释:
(1)串口时钟使能
串口是挂载在
APB2
下面的外设,所以使能函数为:
对应代码段
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//使能USART1,GPIOA时钟
可以看到一个挂载在 APB2 下,一个挂在在APB1下。
(2)串口复位
代码段:
USART_Init(USART2, &USART_InitStructure); //初始化串口1
(3)串口参数初始化
串口初始化是通过
USART_Init()
函数实现的
参数1,就是说你要使用第几个串口,参数二是一个结构体指针,在使用之前我们要对他进行初始化。
//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; //收发模式
这里就波特率和收发模式需要自己设定一下,其他基本固定。
从上面的初始化格式可以看出初始化需要设置的参数为:波特率,字长,停止位,奇偶校验位,
硬件数据流控制,模式(收,发)。我们可以根据需要设置这些参数。
(4)数据的发送与接收
STM32
的发送与接收是通过数据寄存器
USART_DR
来实现的,这是
一个双寄存器,包含了
TDR
和
RDR
。当向该寄存器写数据的时候,串口就会自动发送,当收
到数据的时候,也是存在该寄存器内。
(5)串口状态
串口的状态可以通过状态寄存器
USART_SR
读取。
(6)串口使能
串口使能是通过函数
USART_Cmd()
来实现的:
(7) 开启串口响应中断
有些时候当我们还需要开启串口中断,那么我们还需要使能串口中 断,使能串口中断的函数是:
(8)获取相应中断状态
当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄
存器中的某个标志位。经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
三、关于串口初始化代码的解释
void uart_init(u32 bound);//传入一个unsigned int 型的值,代表波特率,如: uart_init(9600);
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 IO口管脚结构体初始化
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
//初始化PA10,只需要改变9用到的结构体的相应变化位就可以了
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
五、printf()函数
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#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((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
这样使用printf函数的时候,就自动调用fputs函数了。要换别的串口修改一下
六、总结
串口初始化部分:
(1)定义三个结构体GPIO_InitTypeDef、USART_InitTypeDef、NVIC_InitTypeDef
(2)使能时钟,用到的是USART1,GPIOA时钟,这里他们的时钟的定义在stm32f10x_rcc.h文件中有定义。RCC_APB2Periph_USART1和RCC_APB2Periph_GPIOA
(3)初始化三个结构体,结构体成员也能找到.顺带初始化相应管脚和寄存器
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_Init(USART1, &USART_InitStructure); //初始化串口1
(4)开启串口中断,开启串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
串口中断:
(1)获取串口的状态
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
参数1:串口号 参数2:串口的哪种状态
USART_IT_RXNE:判断读寄存器是否非空(RXNE)
USART_IT_TC:判断发送是否完成(TC)
返回值:FlagStatus类型
(2)读取接收到的数据
Res =USART_ReceiveData(USART1); //读取接收到的数据
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)