做網(wǎng)站分成青島網(wǎng)站
線路連接:
????????顯示屏的SCA接在B11,SCL接在B10,串口的RX連接A9,TX連接A10。
程序編寫:
????????在上一個(gè)博客中實(shí)現(xiàn)了串口的發(fā)送代碼,這里實(shí)現(xiàn)串口的接收代碼,在上一個(gè)代碼的基礎(chǔ)上增加程序功能。
Seiral.c初始化函數(shù):
- 初始化A9引腳,設(shè)置為復(fù)用推挽輸出,也就是讓內(nèi)部硬件控制引腳
- 初始化A10引腳,設(shè)置為浮空輸入或上拉輸入,這里使用上拉輸入,具有較好的抗干擾能力
- 不使用硬件流控制,也就是不使用RTS,CTS等
- 串口模式為TX|RX(Transform)|(Receive)表示發(fā)送和接收
- 無校驗(yàn)位,可選擇奇校驗(yàn),偶校驗(yàn)等
- 1位停止位,可選擇0.5 1 1.5 2這幾個(gè)
- 8字長,不需要校驗(yàn)選8位,需要選9位
- 開啟RXNE(RX No Empty)到NVIC的輸出,也就是開啟中斷
- 配置中斷
初始化程序:
void Serial_Init() {RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//開啟時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//開啟時(shí)鐘GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//復(fù)用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空輸入或者上拉輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;//波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(不使用,CTS,CTS&RTS)USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式 可以使用(或)|符號實(shí)現(xiàn)Tx和Rx同時(shí)設(shè)置USART_InitStructure.USART_Parity = USART_Parity_No;//校驗(yàn)位,無需校驗(yàn)USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位,選擇1位USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長USART_Init(USART1, &USART_InitStructure);//串口接收部分可以采用查詢或者中斷的方式,如果采用中斷就需要在這里配置NVIC//開啟中斷USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟RXNE到NVIC的輸出NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);//開啟USART
}
兩種實(shí)現(xiàn)方式:
不使用中斷,直接在主函數(shù)實(shí)現(xiàn):
while(1){if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {RxData = USART_ReceiveData(USART1);//根據(jù)手冊這里讀DR可以自動清除標(biāo)志位OLED_ShowHexNum(1,1,RxData,2);//后面不需要清除標(biāo)志位}}
}
????????這個(gè)代碼就是不使用中斷直接進(jìn)行數(shù)據(jù)接收操作,如程序所示,在主函數(shù)while循環(huán)中,不斷地查詢RXNE標(biāo)志位是否置1,如果置1,則說明數(shù)據(jù)從讀數(shù)據(jù)移位寄存器(RDR)中被轉(zhuǎn)移到了DR寄存器中,表示收到數(shù)據(jù),這時(shí)候,讀取DR寄存器,也就是if成立后下面的代碼,當(dāng)讀取DR寄存器時(shí),RXNE會自動置0,也不需要手動清除標(biāo)志位。這樣就實(shí)現(xiàn)了讀取一個(gè)字節(jié)的數(shù)據(jù)。
使用中斷:
????????在初始化中,已經(jīng)將NVIC初始化,這里編寫中斷函數(shù)
void USART1_IRQHandler() {if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {//如果讀取DR就自動清除標(biāo)志位,如果沒有就需要手動清除Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
? ? ? ? 這里兩個(gè)變量Serial_RxData;?Serial_RxFlag為事先定義好的全局變量,表示收到的數(shù)據(jù)和標(biāo)志位。
????????這里如果沒有讀取RxData數(shù)據(jù)就需要手動清除標(biāo)志位,也就是USART_ClearITPendingBit();這行代碼,為了保險(xiǎn)起見,建議加上這行代碼
????????這里再對這兩個(gè)變量進(jìn)行封裝,也可以使用extern聲明出去,讓別的文件也可以操作這兩個(gè)變量,這里使用函數(shù)封裝,如下面代碼所示,這里RxFlag也實(shí)現(xiàn)了自動清除功能。
uint8_t Serial_GetRxFlag() {if(Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}
uint8_t SerialGetRxData() {return Serial_RxData;
}
主函數(shù)實(shí)現(xiàn):
int main() {OLED_Init();Serial_Init();OLED_ShowString(1, 1, "RxData:");while(1){if(Serial_GetRxFlag() == 1) {RxData = SerialGetRxData();//根據(jù)手冊這里讀DR可以自動清除標(biāo)志位Serial_SendByte(RxData);OLED_ShowHexNum(1,8,RxData,2);//后面不需要清除標(biāo)志位}}
}
函數(shù)代碼:
Serial.c
?
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;void Serial_Init() {RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//開啟時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//開啟時(shí)鐘GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//復(fù)用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空輸入或者上拉輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;//波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(不使用,CTS,CTS&RTS)USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式 可以使用(或)|符號實(shí)現(xiàn)Tx和Rx同時(shí)設(shè)置USART_InitStructure.USART_Parity = USART_Parity_No;//校驗(yàn)位,無需校驗(yàn)USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位,選擇1位USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長USART_Init(USART1, &USART_InitStructure);//串口接收部分可以采用查詢或者中斷的方式,如果采用中斷就需要在這里配置NVIC//開啟中斷USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟RXNE到NVIC的輸出NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);//開啟USART
}
void Serial_SendByte(uint8_t Byte) {USART_SendData(USART1, Byte);//發(fā)送數(shù)據(jù)while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) {//等待發(fā)送寄存器空,//TXE就是發(fā)送寄存器空的標(biāo)志位,不需要手動清零,下一次發(fā)送數(shù)據(jù)時(shí)候會自動清零}
}
void Serial_SendArray(uint8_t *Array, uint16_t Length){uint16_t i;for(int i = 0; i < Length; i++) {Serial_SendByte(Array[i]);}}
void Serial_SendString(char *Str) {//字符串自帶結(jié)束標(biāo)志位uint8_t i;for(int i = 0; Str[i] != '\0'; i++) {Serial_SendByte(Str[i]);}}
uint32_t Serial_Pow(uint32_t X, uint32_t y) {uint32_t Result = 1;while(y--) {Result *= X;}return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length) {uint8_t i;for(int i = 0; i < Length; i++){Serial_SendByte((Number / Serial_Pow(10, Length - i - 1)) % 10 + '0');}}
int fputc(int ch, FILE* f){Serial_SendByte(ch);//重定向到串口,使得Printf打印到串口return ch;}
//使用sprintf讓其他的串口也能使用,sprintf可以把格式化字符輸出到一個(gè)字符串里
void Serial_Printf(char* format,...){//三個(gè)點(diǎn)用來接收后面可變參數(shù)列表char String[100];va_list arg;va_start(arg, format);//從format位置開始接收參數(shù)表,放在arg里面vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}
uint8_t Serial_GetRxFlag() {if(Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}
uint8_t SerialGetRxData() {return Serial_RxData;
}
void USART1_IRQHandler() {if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {//如果讀取DR就自動清除標(biāo)志位,如果沒有就需要手動清除Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
Serial.h?
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>void Serial_Init();
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char* format,...);
uint8_t Serial_GetRxFlag();
uint8_t SerialGetRxData();#endif
main.c
#include "stm32f10x.h" // Device header
#include "DELAY.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
int main() {OLED_Init();Serial_Init();OLED_ShowString(1, 1, "RxData:");while(1){//查詢:在主函數(shù)里一直查看RXNE標(biāo)志位,如果置1則說明收到數(shù)據(jù),再調(diào)用讀取DR寄存器代碼就獲得了數(shù)據(jù)/*if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {RxData = USART_ReceiveData(USART1);//根據(jù)手冊這里讀DR可以自動清除標(biāo)志位OLED_ShowHexNum(1,1,RxData,2);//后面不需要清除標(biāo)志位}*/if(Serial_GetRxFlag() == 1) {RxData = SerialGetRxData();//根據(jù)手冊這里讀DR可以自動清除標(biāo)志位Serial_SendByte(RxData);OLED_ShowHexNum(1,8,RxData,2);//后面不需要清除標(biāo)志位}}
}
程序現(xiàn)象:
程序打包下載:
源碼:源代碼下載
串口助手:串口助手下載