STM32筆記 (九)串口通訊USART(串口發送接收編程)

簡介

串口USART(Universal Synchronous Asynchronous Receiver and Transmitter)也叫通用同步異步收發器,是單片機與外部進行信息交互的重要通信接口,屬於單片機的一種外設,幾乎所有單片機都支持使用串口通訊,同時也是單片機程序調試的一種重要手段,對於STM32,串口資源非常豐富,功能也比較齊全,以STM32F103ZET6爲例,就提供了5路的串口,我們一般用把串口用來在電腦的串口調試工具上打印調試信息,從而瞭解程序運行是否正確、如果出錯的話也能知道是哪裏出了錯誤。

通訊的有關概念

並行通訊

並行就是採用多條數據線進行通訊
優點是傳輸速度快,缺點是佔用的引腳資源多
在這裏插入圖片描述

串行通訊

數據按位順序傳輸,需要的信號線相比於並行通信來說少了很多,最簡單的只需要三根線:RXD,TXD,GND,顯然這種通訊方式的優點是佔用的引腳資源少,缺點是傳輸速率不高
在這裏插入圖片描述

單工

數據傳輸只支持數據在【一個方向上】傳輸
在這裏插入圖片描述

半雙工

允許數據在兩個方向上傳輸,但是,在某一時刻,只允許數據在一個方向上傳輸,它實際上是【一種切換方向】的【單工通信
在這裏插入圖片描述

全雙工

允許數據【同時在兩個方向上傳輸】,因此,全雙工通信是【兩個單工通信方式的結合】,它要求發送設備和接收設備都有獨立的接收和發送能力
在這裏插入圖片描述

同步通訊

帶【時鐘同步信號】傳輸
如IIC通訊需要兩根線,一根是SDA數據線,一根是SCL時鐘線

異步通訊

不帶】【時鐘同步】信號
也就是發出的信號可以不受時鐘線的約束

USART的寄存器

  • 狀態寄存器(USART_SR)
  • 數據寄存器(USART_DR)
  • 波特比率寄存器(USART_BRR)
  • 控制寄存器 1(USART_CR1)
  • 控制寄存器 2(USART_CR2)
  • 控制寄存器 3(USART_CR3)
  • 保護時間和預分頻寄存器(USART_GTPR)

USART的功能框圖

在這裏插入圖片描述

初始化結構體中的各種參數

typedef struct {
	uint32_t USART_BaudRate; // 波特率
	
	uint16_t USART_WordLength; //數據字長
	
	uint16_t USART_StopBits; // 停止位
	
	uint16_t USART_Parity; // 奇偶校驗位選擇
	
	uint16_t USART_Mode; // USART 模式
	
	uint16_t USART_HardwareFlowControl; // 硬件流控制
	
} USART_InitTypeDef;
  • 波特率
    波特率指數據信號對載波的調製速率,它用單位時間內載波調製狀態改變次數來表示,
    單位爲波特,指的是一個設備在一秒鐘內發送(或接收)了多少碼元的數據(碼元:又叫碼率,單位爲波特,一個脈衝信號就是一個碼元),這裏簡單理解爲傳輸數據的速率,波特率的計算有一個固定的公式
    在這裏插入圖片描述
    這裏的fck是USART的時鐘頻率,一般是72MHz,USARTDIV是一個與波特率寄存器(USART_BRR)有關的數,波特率寄存器有16個位,前4個位用於配置USARTDIV的小數部分,後12個位用於配置整數部分,我們可以根據所需要配置的波特率從而算出USARTDIV的值,進而配置波特率寄存器的值
  • 數據字長
    可以選擇8 位或 9 位,具體選擇多少位要看後面檢驗位,如果開啓了奇偶校驗,那麼就選9位,如果沒有的話就選8位,也就是一個bit
  • 停止位
    串口在傳輸完數據的時候會有停止信號,這裏設置的就是停止信號的長度,可選 0.5 個、 1 個、 1.5 個和 2 個停止位,一般選擇1位
  • 奇偶校驗位選擇
    假設傳輸的數據位:1 1 1 0
    那麼偶校驗位會根據數據位中的 1 的個數是否爲偶數來補位(補成偶數個1),如果前面1是三個 那麼此時偶校驗位爲 1 加起來一共有四個 1 是偶數,這時候偶校驗位的值就爲1
    奇校驗位的原理則與之相反
  • USART 模式
    模式分爲:接收模式,發送模式,如果不設置默認不能接收和發送,一般在設置的時候設置成兩種模式都開,也就是收發模式
  • 硬件流控制
    很少用到,一般設置成無硬件數據流控制

初始化USART的流程在這裏插入圖片描述

其中串口的接收端模式配置成浮空輸入輸出端配置成複用推輓輸出,爲什麼這樣配置呢?具體怎麼配置可以在參考手冊的這裏找到
在這裏插入圖片描述

使用串口在串口調試助手上輸出HELLO WORLD

#include "stm32f10x.h"

void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	// 打開串口 GPIO USART1 的時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	//GPIOA_9  USART1 TX 配置爲推輓複用模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//GPIA_10 USART1_RX 配置爲浮空輸入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置USART1的參數
	USART_InitStructure.USART_BaudRate = 115200;// 配置波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置硬件流控制	
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 配置工作模式,收發一起	
	USART_InitStructure.USART_Parity = USART_Parity_No;//配置校驗位	
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//配置停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//配置數據字長
	USART_Init(USART1, &USART_InitStructure);// 完成串口的初始化配置
	
	NVIC_Config();//配置NVIC
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接收中斷
	
	USART_Cmd(USART1, ENABLE);// 使能串口
}

//發送一個Byte
void Usart_SendByte( USART_TypeDef * USARTx, uint8_t ch)
{
	USART_SendData(USARTx,ch); //發送一個字節數據到 USART
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);//等待發送數據寄存器爲空
}

//發送一個字符串
void USART_SendStr(USART_TypeDef *USARTx,uint8_t *str)
{
	uint8_t i = 0;
	do
	{
		Usart_SendByte(USART1,*(str+i));
		i++;
	}while( *(str+i) != '\0');
	
	//等待發送完成
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}

int main(void)
{	
	USART_Config();
	USART_SendStr(USART1,"HELLO WORLD!");
	while(1)
	{
	}
}

void USART1_IRQHandler(void)
{
	uint8_t ucTemp;
	if (USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) 
	{
		ucTemp |= USART_ReceiveData( USART1 );
	}
	USART_SendStr(USART1,"\n收到!");
}

在STM32中使用printf,putchar,scanf,getchar等函數

我們知道這幾個函數是在C語言頭文件stdio.h中的,由於我們使用的是運行於STM32的C語言,所以這幾個函數並不能使用,但是現在我們會使用串口,而串口可以在串口調試工具中輸出調試信息,出於習慣我們如果想使用這幾個函數必須重定向這幾個函數,具體步驟如下:

  1. 聲明頭文件
#include “stdio.h”
  1. 使用以下函數對這四個函數進行重定向
//發送數據
int fputc(int ch, FILE *f) 
{ 
	USART_SendData(USART1, (unsigned char)ch);// USART1 可以換成 USART2 等其他串口 
	while( !USART_GetFlagStatus(USART1,USART_FLAG_TXE) ); //等待數據被轉移到移位寄存器。
	return (ch); 
}
 
// 接收數據 
int GetKey (void)  
{  
	while( !USART_GetFlagStatus(USART1,USART_FLAG_RXNE) ); //等待讀數據寄存器接收到數據
	return ((int)(USART1->DR & 0x1FF)); //數據寄存器有9位,這裏取出9位
 } 
  1. 在工程屬性的 “Target" > “Code Generation” 選項中勾選 “Use MicroLIB”
    在這裏插入圖片描述

如何在打印出數據後換行

在字符串後面加上\r\n即可換行,即

printf("字符串\r\n");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章