点亮LED灯后,基本了解了GPIO口的使用,下面学通过查询方式运用USART1口收发数据。
首先总结全文,通过查询方式运用USART1口收发数据的主要步骤如下:
- 初始化GPIO口
- 初始化串口
- 编写发送数据函数
- 编写主函数
下面介绍详细步骤:
1.初始化GPIO口
通过查阅STM32数据手册可知,stm32f103c8 ,USART1的输入、输出引脚,分别为GPIOA端口的 Pin_10,Pin_9引脚,所以先定义GPIO结构体并赋值:
void IO_Init()
{
GPIO_InitTypeDef Uart_A;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
Uart_A.GPIO_Pin = GPIO_Pin_9;
Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&Uart_A);
Uart_A.GPIO_Pin = GPIO_Pin_10;
Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //stm32 data sheet page 110
GPIO_Init(GPIOA,&Uart_A);
}
还和以前一样,先定义GPIO结构体变量,在使能GPIO外设时钟,紧接着分别对各个引脚的寄存器赋值并初始化。
这里需要注意引脚模式的选择:根据STM32参考手册,在全双工模式下,输出口的引脚(Pin_9)要配置为推挽复用输出,接收口的引脚(Pin_10)要配置为浮空输入或带上拉输入,刚开始学STM32不需要过深了解,只需要知道引脚要配置为相应模式即可。如想深究请查看STM32参考手册110页。
2,初始化串口
要初始化串口可以利用库函数中的串口结构体 USART_InitTypeDef,这样对于初学者来说方便易懂。
库函数中的结构体 USART_InitTypeDef为:
typedef struct
{//波特率
uint32_t USART_BaudRate; /*!< This member configures the USART communication baud rate.
The baud rate is computed using the following formula:
- IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
- FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
//字长
uint16_t USART_WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.
This parameter can be a value of @ref USART_Word_Length */
//停止位
uint16_t USART_StopBits; /*!< Specifies the number of stop bits transmitted.
This parameter can be a value of @ref USART_Stop_Bits */
//是否奇偶校验
uint16_t USART_Parity; /*!< Specifies the parity mode.
This parameter can be a value of @ref USART_Parity
@note When parity is enabled, the computed parity is inserted
at the MSB position of the transmitted data (9th bit when
the word length is set to 9 data bits; 8th bit when the
word length is set to 8 data bits). */
//串口模式,收or发?
uint16_t USART_Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
This parameter can be a value of @ref USART_Mode */
//是否使能硬件流,这个初学者暂时先放放,还用不到(博主现在是初学者)
uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
or disabled.
This parameter can be a value of @ref USART_Hardware_Flow_Control */
} USART_InitTypeDef;
知道了结构体,便可轻松理解下面的定义了。
USART_InitTypeDef Uart;
使能串口时钟后,依次对结构体中的变量赋值(注:STM32的每个外设都有其单独的时钟,只有使能了其时钟,外设才能开始工作)详细代码如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
Uart.USART_BaudRate = 115200;//波特率115200
Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流失能
Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置为 输出和输入模式
Uart.USART_Parity = USART_Parity_No;//不进行奇偶校验
Uart.USART_StopBits = USART_StopBits_1;//1个停止位
Uart.USART_WordLength = USART_WordLength_8b;//单次数据长读为8
USART_Init(USART1,&Uart);//初始化串口
在初始化串口后,按照STM32参考手册还需要对usart使能见下图:
(注:博主当时在这里想到一个问题:STM32有多个串口,但是只有这一个串口使能位,也就是这么多串口公用一个使能位,那么,当使用多个串口工作,如果临时需要关闭一个串口,怎么办?答案见文章最下部分,答案1。)
由上图可知,在初始化串口完毕后,还需要使能串口:
USART_Cmd(USART1,ENABLE);
然后根据参考手册:
此时还需要先清除状态寄存器USART_SR的发送完成(TC)位,要不然发送数据的第一个字节显示不出来。代码如下:
SART_ClearFlag(USART1,USART_FLAG_TC);
到此,串口的初始化也就完成了。
3,编写发送函数
此处比较简单,先说代码:
void sendByte(uchar character)
{
USART1->DR = character;
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
需要发送时,直接把数据赋值给USART1的数据寄存器(USART_DR),即可通过串口发出,接下来需要等待数据发送完毕,当数据发送完毕后,USART的状态寄存器的发送寄存器空(TXE)位会置1,(RESET在库函数的宏定义为 0),即,若数据未发送完成,那么循环会一直空转,直到数据全部转到移位寄存器。
4.编写主函数
本文是通过运用查询方法来实现串口的发送。通过串口向电脑发送一个字符,串口之后会自动向电脑发送已发送字符的后9个。
先粘贴代码在解释:
int main()
{
int count= -1;
char temp= '0';
IO_Init();
Usart1_Init();
while(1){
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))//判断是否接受到数据
{
temp = USART1->DR;//若接收到数据,则将数据从数据寄存器取出
count = 10;
}
if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))//判断能否发送数据
{
while(count >0){
sendByte(temp++);//若能发送数据,则向接收端发送数据
count--;//连着发送10个字符
delay(1000);延时一秒
}
if(count<0){
sendByte('\r');//博主本来想在电脑接收端输出回车换行,但是一直接收不了,还没弄明白。
}
}
}
}
解释见代码中的注释。
答案1:当不需要使用多个串口中的一个时,直接将对应串口外设的时钟失能就可以了。
通过查询方式实现串口收发数据完结。2018年3月20日
下一篇,通过中断来使用串口。
见STM32基础设计(3)---中断串口通信
本文的完整代码如下:
#include<stm32f10x.h>
#define uint unsigned int
#define uchar unsigned char
void delay(uint n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<8500;j++);
}
void IO_Init()
{
GPIO_InitTypeDef Uart_A;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
Uart_A.GPIO_Pin = GPIO_Pin_9;
Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&Uart_A);
Uart_A.GPIO_Pin = GPIO_Pin_10;
Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110
GPIO_Init(GPIOA,&Uart_A);
}
void Usart1_Init()
{
USART_InitTypeDef Uart;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
Uart.USART_BaudRate = 115200;
Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
Uart.USART_Parity = USART_Parity_No;
Uart.USART_StopBits = USART_StopBits_1;
Uart.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&Uart);
USART_Cmd(USART1,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_TC); //page 540
}
void sendByte(uchar character)
{
USART1->DR = character;
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
int main()
{
int count= -1;
char temp= '0';
IO_Init();
Usart1_Init();
while(1){
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))
{
temp = USART1->DR;
count = 10;
}
if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))
{
while(count >0){
sendByte(temp++);
count--;
delay(1000);
}
if(count<0){
sendByte('\r');
}
}
}
}