【STM32F103】USART通用同步异步收发器

串行通信

通信分为串行通信和并行通信,区别如下,同样是发送0101的数据:

可以看的出来,串行通信的优点是消耗的数据线会小一些。

而并行通信的优点是传输的速度快。

通常我们会选择使用串行通信来进行设备间的通信,这样会节省单片机引脚资源,同时传输的速率也是我们可以接受的。

串行通信又分为异步通信和同步通信。

异步通信的数据传输按帧传输,每一帧需要包含起始位,数据位,校验位和停止位,通过起始位和校验位我们就可以确定每帧数据的范围,校验位用来检验传输的数据是否有误。

同步通信由1~2个同步字符和多位数据位组成.同步字符用于触发同步时钟开始发送或是接收数据。多字节数据之间不允许有空隙,每位占用的时间相同。

小总结一下,异步通信对硬件的要求较低,实现起来简单灵活,但由于传输每个字节都需要建立一次同步,所以工作速度较低,单片机系统中主要是用异步通信。同步通信对硬件要求高,但是传输速度快,适用于成批的数据传输。

STM32F103中的USART

STM32F103C8T6一共有三个USART外设资源,具体的功能引脚可以参考下图(来自b站江科大自化协)

接线的时候需要注意的是,两个设备之间通信,设备A的RX(接收端)需要接到设备B的TX(发送端),设备A的TX(发送端)需要接到设备B的RX(接收端)。所以两个设备之间使用串行通信只需要两根线即可,可以看出来确实是很节省引脚资源,甚至如果A不需要发送数据只需要接收的话,是连TX(发送端)都不用连的。

根据手册的参考,我们需要将TX的GPIO口设置为推挽复用输出,RX的GPIO口设置为浮空输入或是上拉输入(和传输有关的我们设置为浮空输入)。

以下是官方给的参考手册的介绍:

随便看看就好,不影响我们的编程,因为官方固件库都给我们封装好了。

固件库函数

 初始化USART

参数一选择USART资源,STM32F103C8T6可以选的有USART1,USART2,USART3,要看准对应的引脚,不要接错了。

参数二参数USART_InitStruct类型的变量,通过这个变量的成员来对USART进行配置。

USART_BandRate:波特率,常用的有9600,115200等,最主要的是发送端和接收端的配置要一样,这样才可以进行通信。

USART_WordLength:传输的字长,可选的参数有USART_WordLength_8b或是USART_WordLength_9b。一般是选择8b,如果有校验位的话也就是加一位选9b。

USART_StopBits:停止位长度,一般选择USART_StopBits_1。这个和波特率一样没有什么特定需求,只需要发送方和接收方配置一样就行。

USART_Parity:校验,可以选择奇校验,偶校验,或者是不校验。奇校验就是在传输的数据后面再加一位校验位,在接收方收到数据之后,把接收到的数据(包括校验位)集中起来统计一下1出现的次数,如果为奇数那么就表示数据无误(实际上还是有可能是有问题的),偶校验和奇校验差不多,区别在于偶校验要求1出现的次数为偶数。如果选择了校验,那么上面的字长需要选择9b的选项。

USART_Mode:USART传输的模式,可选的有USART_Mode_RX和USART_Mode_TX。分别表示选择接收模式和发送模式,如果都要的话,可以用|连接起来,填入参数为USART_Mode_Rx|USART_Mode_Tx。

USART_HardwareFlowControl:硬件控制流选择,一般情况下用不着,我们选择USART_HardwareFlowControl_None即可。

上电USART

参数一选择USART资源,参数二选择是否使能(ENABLE/DISABLE)。

初始化和上电之后就可以开始发送数据了。

发送数据

参数一选择USART资源,参数二选择要传输数据。

这个函数执行完我们还需要等待数据传输完毕,等待的方法就是不断访问对应的标志位,直到标志位显示发送完毕即可。

查看标志位

参数一选择USART资源,参数二选择要访问的标志位。

检测发送是否完毕我们选择USART_FLAG_TXE

检测是否有数据可以接收USART_FLAG_RXNE

发送数据完毕之后标志位会自动置回去,所以我们不需要管。如果是接收数据的话,在接收完毕之后我们还要把对应的标志位手动清除。

清除标志位

参数一选择USART资源,参数二选择要清除的参数。

如果是只需要发送数据的话那么上面的函数就够用了,但如果还要接收数据的话还需要配置一下中断。

配置USART中断

参数一选择USART资源,参数二选择因为什么而中断,我们选择USART_IT_RXNE,即接收到数据之后进入中断,进入中断之后要根据上面的函数来获取标志位,清除标志位,然后再用接收数据的函数来获取数据。参数三选择ENABLE。

除了这个函数配置完中断之后还需要配置一下NVIC中断优先级配置,本文主要是讲USART的,就不细说,可以参考下面给出的代码。有关中断的内容,我后续专门写中断配置的时候会补上。

配置中断完毕之后,使用的中断函数为void USART1_IRQHandler(void)

中断函数的函数名可以在文件“startup_stm32f10x_md.s”中找到。

接收数据

参数一选择USART资源,返回接收到的数据。

这个函数我们在中断里调用,在上一条配置完中断以后,收到数据之后进入中断,然后使用这条函数来获取数据。

接线

使用USB转TTL的模块将STM32F103C8T6连接到电脑上,然后电脑上使用串口助手来查看传输的结果。我使用的串口助手是b站江科大自化协提供的,大家随便上网搜一个串口助手都能用。

将USB转TTL模块的RX接到STM32F103C8T6的USART1_TX(GPIOA的10号口)上,TX接到USART1_RX(GPIOA的9号口)上。

代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                      //延时函数
#include "OLED.h"                       //OLED显示屏驱动函数

//中断函数
void USART1_IRQHandler(void){
    //判断数据接收标志位
    if(SET==USART_GetFlagStatus(USART1,USART_FLAG_RXNE)){
        uint16_t data=USART_ReceiveData(USART1);            //读取出接收的数据
        OLED_ShowHexNum(2,1,data,4);                        //使用OLED显示接收的数据
        USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);    //清除数据接收标志位
    }
}

void sendbyte(uint16_t Data){
    //发送数据
    USART_SendData(USART1,Data);
    //等待数据发送完毕
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}


int main(void){
    OLED_Init();
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_AF_PP;      //复用推挽输出
    itd.GPIO_Pin=GPIO_Pin_9;            //TX引脚
    itd.GPIO_Speed=GPIO_Speed_2MHz;     //这个随意
    GPIO_Init(GPIOA,&itd);
    itd.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
    itd.GPIO_Pin=GPIO_Pin_10;           //RX引脚
    GPIO_Init(GPIOA,&itd);
    
    USART_InitTypeDef uitd;
    uitd.USART_BaudRate=9600;                                       //波特率
    uitd.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //硬件流控制
    uitd.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;                    //串口模式
    uitd.USART_Parity=USART_Parity_No;                              //校验
    uitd.USART_StopBits=USART_StopBits_1;                           //停止位长度
    uitd.USART_WordLength=USART_WordLength_8b;                      //传输的字长
    USART_Init(USART1,&uitd);
    
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                    //开启USART接收中断
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 //NVIC中断配置
    NVIC_InitTypeDef nitd;
    nitd.NVIC_IRQChannel=USART1_IRQn;
    nitd.NVIC_IRQChannelCmd=ENABLE;
    nitd.NVIC_IRQChannelPreemptionPriority=2;
    nitd.NVIC_IRQChannelSubPriority=2;
    NVIC_Init(&nitd);
    
    USART_Cmd(USART1,ENABLE);                                       //上电USART
    
    uint16_t data=0x00;
    while(1){
        sendbyte(data);
        data++;
        Delay_ms(500);
    }
}

效果

使用USART将调试信息打印到电脑的串口助手上

第一步先对Keil进行设置

选中魔术棒再勾上Use MicroLIB。

第二步加入库文件

#include <stdio.h>

第三步重写fputs函数,可以参考下面的写法。因为printf函数的底层就是调用的fputs函数,所以我们只需改写fputs即可。

int fputc(int ch, FILE *f){
    //sendbyte为自己写的发送一个数据的函数
    sendbyte(ch);
    return ch;
}

接下来就可以在程序中使用printf这个函数了,打印的内容会通过USART传输到电脑上,可以通过串口助手来查看。

代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

#include <stdio.h>

//中断函数
void USART1_IRQHandler(void){
    //判断数据接收标志位
    if(SET==USART_GetFlagStatus(USART1,USART_FLAG_RXNE)){
        uint16_t data=USART_ReceiveData(USART1);            //读取出接收的数据
        OLED_ShowHexNum(2,1,data,4);                        //使用OLED显示接收的数据
        USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);    //清除数据接收标志位
    }
}

void sendbyte(uint16_t Data){
    //发送数据
    USART_SendData(USART1,Data);
    //等待数据发送完毕
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

int fputc(int ch, FILE *f){
    sendbyte(ch);
    return ch;
}

int main(void){
    OLED_Init();
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_AF_PP;      //复用推挽输出
    itd.GPIO_Pin=GPIO_Pin_9;            //TX引脚
    itd.GPIO_Speed=GPIO_Speed_2MHz;     //这个随意
    GPIO_Init(GPIOA,&itd);
    itd.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
    itd.GPIO_Pin=GPIO_Pin_10;           //RX引脚
    GPIO_Init(GPIOA,&itd);
    
    USART_InitTypeDef uitd;
    uitd.USART_BaudRate=9600;                                       //波特率
    uitd.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //硬件流控制
    uitd.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;                    //串口模式
    uitd.USART_Parity=USART_Parity_No;                              //校验
    uitd.USART_StopBits=USART_StopBits_1;                           //停止位长度
    uitd.USART_WordLength=USART_WordLength_8b;                      //传输的字长
    USART_Init(USART1,&uitd);
    
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                    //开启USART接收中断
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 //NVIC中断配置
    NVIC_InitTypeDef nitd;
    nitd.NVIC_IRQChannel=USART1_IRQn;
    nitd.NVIC_IRQChannelCmd=ENABLE;
    nitd.NVIC_IRQChannelPreemptionPriority=2;
    nitd.NVIC_IRQChannelSubPriority=2;
    NVIC_Init(&nitd);
    
    USART_Cmd(USART1,ENABLE);                                       //上电USART
    
    uint16_t data=0;
    while(1){
        printf("Hello World! %d\r\n",data);
        data++;
        Delay_ms(500);
    }
}

效果

 串口助手需要改成接收文本模式。

参考

b站江科大自化协

《STM32F10xxx参考手册(中文)》

《ARM Cortex-M3 嵌入式原理及应用 基于STM32F103微控制器》

  • 30
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值