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』