1. 簡介
序列槽全稱:Universal synchronous asynchronous receiver transmitter,中文名稱:通用同步異步串行接收發送器。序列槽可用于接收和發送資料,可以用作跟其他裝置通訊,如藍牙子產品、GSM子產品、GPS子產品等。
序列槽中最常見的是RS-232,共有9根線用于通訊,但常用的僅3根線:RXD、TXD、GND。其中RXD用于接收,TXD用于發送,GND為信号地線,兩個通訊裝置之間的收發信号(RXD與TXD)應交叉相連。
2. 基本概念
- 波特率:序列槽異步通訊中由于沒有時鐘信号,是以兩個通訊裝置之間需要約定好波特率,即每個碼元的長度,以便對信号進行解碼,常見的波特率為4800、9600、115200 等。波特率越高傳輸速度越快,但出錯的機率要更大。
- 通訊的起始和停止信号:序列槽通訊的一個資料包從起始信号開始,直到停止信号結束。資料包的起始信号由一個邏輯 0 的資料位表示,而資料包的停止信号可由 0.5、1、1.5或 2個邏輯 1的資料位表示,隻要雙方約定一緻即可。
- 有效資料:在資料包的起始位之後緊接着的就是要傳輸的主體資料内容,也稱為有效資料,有效資料的長度常被約定為 5、6、7或 8位長。
- 資料校驗:在有效資料之後,有一個可選的資料校驗位。由于資料通信相對更容易受到外部幹擾導緻傳輸資料出現偏差,可以在傳輸過程加上校驗位來解決這個問題。校驗方法有奇校驗(odd)、偶校驗(even)、0校驗(space)、1校驗(mark)以及無校驗(noparity)。奇校驗要求有效資料和校驗位中“1”的個數為奇數,偶校驗與奇校驗要求剛好相反,要求幀資料和校驗位中“1”的個數為偶數,0校驗是不管有效資料中的内容是什麼,校驗位總為“0”,1校驗是校驗位總為“1”。
- 常用的設定:波特率9600,8位資料位,1位停止位,無校驗位,無硬體流控。
序列槽USART分為兩部分,初始化和處理。
1. 初始化分三步:GPIO、通用中斷、USART。
1.1. GPIO:時鐘、引腳、輸入輸出模式、端口初始化
- 時鐘:需要同時使能GPIO時鐘
- 引腳:需要選擇指定的引腳
- 輸入輸出模式:TX引腳選擇複用推挽模式,RX引腳選擇浮空輸入模式
- 端口初始化:初始化指定的端口
1.2. 通用中斷:優先級分組、中斷源、優先級、使能
- 優先級分組:設定合适的優先級分組
- 中斷源:選擇指定的中斷源:USART1_IRQn
- 優先級:設定合适的優先級
- 使能:調用庫函數即可,可選擇使能多個中斷,一般情況下隻使能接收中斷。
1.3. USART:時鐘、波特率、資料字長、停止位、校驗位、硬體流控制、工作模式、初始化、使能。
結構體
typedef struct {
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
- 時鐘:需要使能USART1時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- 波特率:一般可選的設定項包括4800、9600、115200等,常用的波特率為9600。
USART_InitStructure.USART_BaudRate = 9600;
- 資料字長:可選8位或9位,常用的是8位。
USART_InitStructure.USART_BaudRate = 9600;
- 停止位:可選0.5、1、1.5、2個,常用的是1個停止位。
USART_InitStructure.USART_BaudRate = 9600;
- 奇偶校驗:可選無校驗、奇校驗和偶校驗,常用的是無校驗。
USART_InitStructure.USART_Parity = USART_Parity_No;
- 模式:可選發送、接收,或者同時啟用,一般都是同時啟用。
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- 硬體流控:可選有使能RTS、使能CTS、同時使能、不使能,一般選擇不使能。
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- 初始化配置
USART_Init(USART1, &USART_InitStructure);
- 使能
USART_Cmd(USART1, ENABLE);
2. 處理
處理分為接收和發送。
接收處理通常放在中斷中,中斷服務函數名稱為USART1_IRQHandler(),調用庫函數USART_ReceiveData()得到接收的資料,并自動清除接收中斷标志位;
發送直接調用庫函數USART_SendData()即可,發送完成之後會調用函數來擷取相應标志來實作發送完成等待功能,即USART_SendData()函數傳回時,相應的資料已經確定發送完成,并可發送下一個資料,發送不同類型的資料可以封裝成不同的函數,但最終都是調用USART_SendData()函數。
接收:
// 序列槽中斷服務函數
void USART1_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
ucTemp = USART_ReceiveData(USART1);
}
}
發送:
//發送一個位元組
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
//發送一個位元組資料到USART
USART_SendData(pUSARTx,ch);
//等待發送資料寄存器為空,即發送完成
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
//發送一個數組
void Usart_SendArray(USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
//發送字元串
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
完整代碼(僅自己編寫的部分) void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中斷控制器組選擇 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART為中斷源 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
/* 搶斷優先級*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子優先級 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中斷 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
void USART_Config(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打開序列槽GPIO的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 打開序列槽外設的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// 将USART Tx的GPIO配置為推挽複用模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 将USART Rx的GPIO配置為浮空輸入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置序列槽的工作參數
// 配置波特率
USART_InitStructure.USART_BaudRate = baudrate;
// 配置 幀資料字長
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
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);
// 序列槽中斷優先級配置
NVIC_Configuration();
// 使能序列槽接收中斷
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 使能序列槽
USART_Cmd(USART1, ENABLE);
}
//發送一個位元組
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
//發送一個位元組資料到USART
USART_SendData(pUSARTx,ch);
//等待發送資料寄存器為空,即發送完成
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
//發送數組
void Usart_SendArray(USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i = 0; i < num; i++)
{
/* 發送一個位元組資料到USART */
Usart_SendByte(pUSARTx, array[i]);
}
/* 等待發送完成 */
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}
//發送字元串
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
{
uint32_t k = 0;
do
{
Usart_SendByte(pUSARTx, *(str + k));
k++;
} while(*(str + k)!='0');
/* 等待發送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
//發送16位數
void Usart_SendHalfWord(USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch & 0xFF00) >> 8;
/* 取出低八位 */
temp_l = ch & 0xFF;
/* 發送高八位 */
USART_SendData(pUSARTx, temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 發送低八位 */
USART_SendData(pUSARTx, temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
// 序列槽中斷服務函數
void USART1_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
ucTemp = USART_ReceiveData(USART1);
USART_SendData(USART1, ucTemp);
}
}
int main(void)
{
USART_Config(9600);
Usart_SendString(USART1, "Hello World!n");
while(1)
{
}
}
仿真結果
1. 發送
編譯完成後,點選
開始仿真,點選
,打開序列槽監視序列槽(點選右側的箭頭可以選擇第幾個序列槽),然後運作程式,可以在序列槽監視視窗看到序列槽發送的資訊。
2. 接收
如果想要仿真序列槽接收,需要使用虛拟序列槽軟體vspd,下載下傳安裝完成後,運作該軟體:
可以看到左側有COM1-5共 5個實體序列槽,點選右側的添加端口,可以添加COM6和COM7兩個虛拟序列槽,并自動連接配接這兩個序列槽。
此時可以打開2個序列槽工具,分别設定為COM6和COM7,并分别發送資料,看看對方是否能夠正常接收,如果可以,表示虛拟序列槽添加并連接配接成功,此時在序列槽工具中關閉COM6。
運作KEIL,并開始仿真後,在COMMAND序列槽中輸入
MODE COM6 9600,0,8,1
ASSIGN COM6 <S1IN> S1OUT
第一條指令設定COM6波特率9600,無校驗位,8個資料位,1個停止位,注意這裡的設定應該與程式中序列槽的設定保持一緻。
第二條指令将COM6和單片機的第一個序列槽進行綁定,即單片機第一個序列槽的收發資料通過計算機的COM6進行收發。
此時在序列槽工具打開COM7,并通過序列槽工具發送資料,程式即可接收到發送的資料。
從上圖可以看到從COM7發送了一個A給單片機,單片機接收到了A,并将A又發送出去,COM7接收到了A。
是以,通過虛拟序列槽軟體,即可在無開發闆、無序列槽線、無序列槽裝置的情況下,通過序列槽工具即可調試序列槽接收及發送程式,實作純軟體環境調試。
學習資料分享交流群:1093776732 入群有全套學習視訊資料電子書免費贈送!
參考資料:
嵌入式開發直播課 - STM32 USART序列槽的應用www.makeru.com.cn
物聯網開發入門直播課 - 基于STM32講解序列槽操作www.makeru.com.cn
物聯網開發入門直播課 - 通過Z-stack協定棧實作序列槽透傳www.makeru.com.cn 嵌入式開發直播課 - 帶你揭曉STM32定時器深藏不露的絕技www.makeru.com.cn
物聯網STM32入門 - 帶你揭曉STM32定時器深藏不露的絕技www.makeru.com.cn