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位數據時,便檢測停止位,檢測完畢後,表示一幀數據發送完畢,開始準備接受下一幀數據。爲了確保數據準確性,通常會在數據位之後設置校驗位。

串行通信的數據幀的格式由起始位、數據位、奇偶校驗位(可選)和停止位等部分組成,如圖:

 

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

 

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

 

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

 

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

 

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

 

測試結果:

 

 

歡迎關注微信公衆號『OpenSSR』

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章