STM32单片机学习笔记——USART串口通信

2019-07-21 04:28发布

首先,USART是什么呢?

USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。(来自百度)

这是官方解释,而我对它的通俗解释是:这是一个用于和其他设备(如电脑、单片机等)通信(交换数据、信息等)的端口,就像手机数据线那样。

当然,这只是我的一种通俗看法,大家经过了深入的学习之后,一定会产生更为准确、成熟的看法。

我所学习的,就是通过这个模块来实现单片机和电脑之间的通信,并以此为基础,实现利用电脑来简单地控制单片机的目的。

那么,我们来简单地看一看我们这段代码由哪几部分组成:

1. 用于存储相关配置的结构体。

2. 变量Temp,用于存储从电脑接收到的信息。

3. 配置TX、RX、时钟、串口、LED灯。

4. 预先设置LED灯关闭的一段代码。

5. 主函数,实现接收数据、改变灯的亮灭状态。

好了,代码结构就是这样了,下面我们来具体地分析一下代码。



1. 结构体:


GPIO_InitTypeDef GPIO_LED_InitStructure;

GPIO_InitTypeDef GPIO_USART_TX_InitStructure;

GPIO_InitTypeDef GPIO_USART_RX_InitStructure;

USART_InitTypeDef USART_InitStructure;

我们先来看一下“GPIO_InitTypeDef”,这是定义在“stm32f10x_gpio.h”里面的结构体,用于存储相关的配置信息。
同理,“USART_InitTypeDef”也是这样,它们是存储两个不同寄存器配置的结构体。
然后,我们看右面的结构体名。这些名字没有什么特殊含义,定义成其他名字也不影响使用。我把它们定义成这个名字就是为了和它们对应的寄存器相匹配。
我一共定义了四个结构体,第一个是LED灯的配置信息,第二个是USART的TX寄存器的配置信息,
第三个是USART的RX寄存器的配置信息,第四个是USART的配置信息。
好了,结构体的说明就到此结束。

2. 变量Temp:

这个没有什么需要多说的,只需要注意它的变量类型,这决定了它能够存储什么样的信息。

3. 配置信息:

先上代码:
        // 配置时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
        // 配置USART_TX
        GPIO_USART_TX_InitStructure.GPIO_Pin =  GPIO_Pin_9;
        GPIO_USART_TX_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_USART_TX_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
       
        GPIO_Init(GPIOA, &GPIO_USART_TX_InitStructure);
       
        // 配置USART_RX
        GPIO_USART_RX_InitStructure.GPIO_Pin =  GPIO_Pin_10;
        GPIO_USART_RX_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

        GPIO_Init(GPIOA, &GPIO_USART_RX_InitStructure);
       
        // 配置串口
        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
       
        USART_Init(USART1, &USART_InitStructure);
       
        USART_Cmd(USART1, ENABLE);


-----------------------------------------------------------------------------------------------------------------------------

        //配置灯
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

        GPIO_LED_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_LED_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_LED_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOB, &GPIO_LED_InitStructure);




这就是完整的配置信息了。

配置的过程很简单,就是将配置信息赋值给相应的结构体成员,然后调用配置函数,由函数将配置信息写到单片机中。

先从时钟说起吧,“RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);”,这句就是来开启GPIOA时钟的。
当然,根据单片机的布线不同,相应的GPIO可能不是A,这个就灵活应变吧。
然后是“RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);”,这句是来开启USART1的时钟的。
同样,根据单片机的布线不同,相应的USART也有可能不是1。
这两个时钟是必需打开的,否则就不能使用相应的功能了。
这里有个比喻:“时钟就是心脏。”,这句话说的一点没错。即使不需要即使功能也要打开时钟。
(我有点觉得这个时钟其实不是用来计时的……)

然后来配置TX。
TX,就是输出单元,指的是单片机用来给电脑(或其他设备)发送数据的寄存器。
我的单片机上的TX位于Pin9,是Pin9的复用功能,所以就有了第七和第八行的代码。
然后速度设为50MHz,这个可以变更,但没有必要。速度快一点不是很好吗?
这三项配置好后,就可以调用GPIO_Init()来将其配置到单片机里面了。

然后是RX。
RX,相应的就是输入单元。
相似的,它位于Pin10,模式是浮动输入(当然了……)。
输入单元不用配置速度,因为它是被动输入,没有速度这种说法……
同样,调用GPIO_Init()函数配置一下。

然后是串口。
串口的配置主要包括:波特率、字长、停止位、奇偶校验位、模式、硬件控制流等。
波特率就设为115200(原因我也不懂,大多这么设……自嘲一个……);
字长就设为8位,一个字节;停止位就设为1;
校验位现在不需要,就设为No(就一个字节的信息还校验什么啊……);
模式为TX和RX;
硬件控制流也不需要,设为None。
好了,现在调用USART_Init()来配置好。
这还不够,我们还需要“使能”USART,就是让它工作的意思。调用USART_Cmd()函数就行了。

最后是LED。
我把打开GPIOB时钟的代码写到这里了,好像有点不合理……和之前一样,只是把A改为了B。
我的单片机上的LED位于Pin0,引脚模式为输出,速度为50MHz。

至此,配置完毕。

4. LED预代码:

我起了一个高大上的名字,但其实就一段……

        //关闭灯
        GPIO_SetBits(GPIOB, GPIO_Pin_0);



我让灯先处于关闭的状态,当然,也可以让它先处于打开的状态,只要将“Set”改为“Reset”就行了。

5. 主函数:

这个主函数并不是main()函数的意思,是主要共嫩函数的意思。


        while (1)
        {
                if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
                {               
                        temp = USART_ReceiveData(USART1);
                        USART_SendData(USART1,temp);
                        GPIOB->ODR ^=GPIO_Pin_0;
                }

        }




将函数主体套在while死循环里,保证单片机一直在执行主要功能(保证它不罢工……)。
调用USART_GetFlagStatus()函数来检查单片机是否接收到来自电脑(或其他设备)的信息,如果是,则执行之后的代码。
将接收到的信息保存在Temp变量中,再将其发送给电脑(或其他设备)。
之后,改变LED的电平状态,实现由亮转灭和由灭转亮。


OK,到此为止,所有代码结束。最后附上完整版代码。



#include "stm32f10x.h"

GPIO_InitTypeDef GPIO_LED_InitStructure;

GPIO_InitTypeDef GPIO_USART_TX_InitStructure;

GPIO_InitTypeDef GPIO_USART_RX_InitStructure;

USART_InitTypeDef USART_InitStructure;

int main()
{
       
        unsigned short int temp;
       
        // 配置时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
        // 配置USART_TX
        GPIO_USART_TX_InitStructure.GPIO_Pin =  GPIO_Pin_9;
        GPIO_USART_TX_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_USART_TX_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
       
        GPIO_Init(GPIOA, &GPIO_USART_TX_InitStructure);
       
        // 配置USART_RX
        GPIO_USART_RX_InitStructure.GPIO_Pin =  GPIO_Pin_10;
        GPIO_USART_RX_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

        GPIO_Init(GPIOA, &GPIO_USART_RX_InitStructure);
       
        // 配置串口
        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
       
        USART_Init(USART1, &USART_InitStructure);
       
        USART_Cmd(USART1, ENABLE);
       
        //配置灯
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
       
        GPIO_LED_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_LED_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_LED_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
       
        GPIO_Init(GPIOB, &GPIO_LED_InitStructure);
       
        //关闭灯
        GPIO_SetBits(GPIOB, GPIO_Pin_0);
       
        while (1)
        {
                if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
                {               
                        temp = USART_ReceiveData(USART1);
                        USART_SendData(USART1,temp);
                        GPIOB->ODR ^=GPIO_Pin_0;
                }

        }
}















友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
一直在路上1
1楼-- · 2019-07-21 05:45
STM32 USART串口的应用的视频资料     http://www.makeru.com.cn/live/detail/1290.html?s=45051      
秋天
2楼-- · 2019-07-21 05:54
谢谢分享
heiyue
3楼-- · 2019-07-21 11:36
对初学者的我太有用了
日月星辰123
4楼-- · 2019-07-21 12:50
学习了

一周热门 更多>