STM32F103入门 | 14.USART串口通信

 

14.1 USART定义

USART(Universal Synchronous/Asynchronous Receiver/Transmitter,即通用同步/异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。


14.2 USART串行通信协议

14.2.1 波特率和数据格式

USART通信中的同步通信功能很少用到,大多情况下只采用异步通信,只能实现异步通信功能的接口就称之为 UART。UART 通信通常以字节为单位组成数据帧,由通信收发双方根据预先约定的波特率(传输速率)进行通信。

波特率表示每秒发送二进制数据位的速率,单位是 bps,即 位/秒,波特率越高,传输速度越快,常用的 UART 通信波特率有2400,4800,9600,115200 等等。在进行串行通信之前,通信双方需要设置波特率保持一致,否则不能正常通信。

单片机标准串口进行通信时,没有数据传输时通信线路保持高电平状态。当要发送数据时,先发送一位0,用以表示开始发送,叫做起始位。然后再按照低位在前,高位在后的顺序发送8位数据。当8位数据发送完毕时,再发送一位1表示停止位。

对于接收端而言,开始时传输线路一直保持高电平,一旦检测到低电平,便准备开始接收数据。当接收完8位数据时,便检测停止位,检测完毕后,表示一帧数据发送完毕,开始准备接受下一帧数据。为了确保数据准确性,通常会在数据位之后设置校验位。

串行通信的数据帧的格式由起始位、数据位、奇偶校验位(可选)和停止位等部分组成,如图:

 

STM32F103入门 | 14.USART串口通信_第1张图片

14.2.2 TTL通信接口和RS232通信接口

电脑和单片机之间进行串口通信,通常使用USB转UART芯片,将USB通信协议转成UART协议和单片机通信。

 

14.3 USART配置步骤

1.时钟使能
2.设置中断分组
3.串口复位
4.GPIO初始化(TX,RX引脚)
5.设置中断分组
6.串口初始化
7.开启中断
8.使能串口

 

1. 新建两个文件,usart.c 和 usart.h

STM32F103入门 | 14.USART串口通信_第2张图片

 

2. 在头文件 usart.h 添加下面代码:

#ifndef _USART_H
#define _USART_H
#include "stdio.h"
#include "stm32f10x.h" 

#define USART_REC_LEN        200      //定义最大接收字节数 200
#define EN_USART1_RX         1        //使能(1)/禁止(0)串口1接收

extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;                //接收状态标记

void usart_init(u32 bound);

#endif

 

STM32F103入门 | 14.USART串口通信_第3张图片

3. 把 usart.c 添加到工程中

STM32F103入门 | 14.USART串口通信_第4张图片

 

4. 在 usart.c 中添加以下代码:

#include "usart.h"

#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;
}

#if EN_USART1_RX                    //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,    接收完成标志
//bit14,    接收到0x0d
//bit13~0,    接收到的有效字节数目
u16 USART_RX_STA = 0;                //接收状态标记

void usart_init(u32 bound){

    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    //使能USART1,GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //配置中断优先级分组
    
    //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;               //PA.10
    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);            //根据指定的参数初始化NVIC寄存器

    //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;
    
    //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
    {
        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; //接收数据错误,重新开始接收
                }
            }
        }
        /*---- User Code Begin ----*/
        
        /*---- User Code End ----*/
    }
}
#endif

 

STM32F103入门 | 14.USART串口通信_第5张图片

STM32F103入门 | 14.USART串口通信_第6张图片

STM32F103入门 | 14.USART串口通信_第7张图片

STM32F103入门 | 14.USART串口通信_第8张图片

STM32F103入门 | 14.USART串口通信_第9张图片

5. 实现USART串口通信(以printf函数为例)

 

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "tim.h"
#include "key.h"
#include "pwm.h"
#include "usart.h"

int main(void)
{
    delay_init();
    usart_init(115200);
    
    printf("USART Init Complete.\r\n");
    while(1)
    {
        printf("Hello World !\r\n");
        delay_ms(500);
    }
}

STM32F103入门 | 14.USART串口通信_第10张图片

 

测试结果:

STM32F103入门 | 14.USART串口通信_第11张图片

 

 

欢迎关注微信公众号『OpenSSR』

STM32F103入门 | 14.USART串口通信_第12张图片

你可能感兴趣的:(STM32F1)