1.寄存器輪詢_收發字符串
通過寄存器輪詢方式實現了收發單個字節之后,我們趁熱打鐵,爭上游,進階到字符串。字符串就是多個字符。很明顯可以循環收發單個字節實現。
然后就是接收字符串。如果接受單個字符的函數放在while里,它也可以實現一個一個的接收字符串,在一定時間戳下,效果等同。
然后我們要想想如何整合,寫成一個函數。
2.問題解答,狀態位清零
我們的編程方式,一個是寄存器寫法,一個是hal庫寫法。還有的就是實現思路。
//發送一個字符
void USART_SendChar(uint8_t ch)
{//判斷TDR是否為空,必須等待TDR為空才能寫入數據,也就是繼續發送while((USART1->SR & USART_SR_TXE)==0){}//將要發送的數據寫入TDRUSART1->DR = ch;
}
初始的時候,TDR的存儲寄存器肯定為空
關于狀態位清零,TXE和RXNE都可以自動清零。
只要發數據,就自動清零。
RXNE也是一樣,只要讀RDR,就會清零。
3.串口通訊 寄存器中斷方式
復制上一個工程文件,把改刪除的刪掉。
主要配置中斷管理NVIC
中斷服務函數
main.c
#include "usart.h"
#include "delay.h"
#include <string.h>
//定義接收緩沖區和接收數據長度
uint8_t buff[100];
uint8_t size;
int main(void)
{//1.初始化USART_Init();//發送單個字符USART_SendChar('A');USART_SendChar('\n');//發送字符串uint8_t str[]="Hello World!\n";USART_SendString(str,strlen((char *)str));while(1){}}
usart.c
#include "usart.h"//初始化
void USART_Init(void)
{//開啟時鐘RCC->APB2ENR |= RCC_APB2ENR_USART1EN;RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//GPIO工作模式// PA9:TX 復用推挽輸出,CNF=10,MODE=11GPIOA->CRH |= GPIO_CRH_MODE9;GPIOA->CRH |= GPIO_CRH_CNF9_1;GPIOA->CRH &= ~GPIO_CRH_CNF9_0;// PA10:RX 浮空輸入,CNF=01,MODE=00GPIOA->CRH &= ~GPIO_CRH_MODE10;GPIOA->CRH &= ~GPIO_CRH_CNF10_1;GPIOA->CRH |= GPIO_CRH_CNF10_0;//串口模塊設置//設置波特率 115200USART1->BRR = 0x271;//使能串口和收發模塊USART1->CR1 |= USART_CR1_UE;USART1->CR1 |= (USART_CR1_TE|USART_CR1_RE);//配置數據幀格式USART1->CR1 &=~ USART_CR1_M; //長度為8位的數據,沒有校驗位USART1->CR1 &=~ USART_CR1_PCE; //無校驗,不使用校驗位USART1->CR2 &=~ USART_CR2_STOP; //1位停止位//使能串口接收中斷USART1->CR1 |= USART_CR1_RXNEIE;USART1->CR1 |= USART_CR1_IDLEIE;//配置NVICNVIC_SetPriorityGrouping(3);NVIC_SetPriority (USART1_IRQn,2);NVIC_EnableIRQ(USART1_IRQn);}//發送一個字符
void USART_SendChar(uint8_t ch)
{//判斷TDR是否為空,必須等待TDR為空才能寫入數據,也就是繼續發送while((USART1->SR & USART_SR_TXE)==0){}//將要發送的數據寫入TDRUSART1->DR = ch;
}//發送字符串,數組可以用指針表示,形參就是數組和字長
void USART_SendString(char *str,uint8_t size)
{uint8_t i = 0;for ( i = 0; i < size; i++){USART_SendChar(str[i]);}}//引入外部變量
extern uint8_t buff[100];
extern uint8_t size;//中斷服務程序
void USART1_IRQHandler(void)
{//判斷是RXNE=1還是IDLE=1if (USART1->SR & USART_SR_RXNE){//如果RXNE=1,表示接收到一個字符
buff[size]=USART1->DR;
size++;}else if (USART1->SR & USART_SR_IDLE){USART1->DR;//如果IDLE=1,表示檢測到空閑幀,字符串接收完畢USART_SendString(buff,size);size=0;}}
usart.h
#ifndef __USART_H
#define __USART_H
#include "string.h"
#include "stm32f10x.h"
//初始化
void USART_Init(void);//發送一個字符
void USART_SendChar(uint8_t ch);//發送一個字符串,數組可以用指針表示,形參就是數組和字長
void USART_SendString(char *str,uint8_t size);#endif
?
我們可以將接收字符串的標志位在外面定義出來。
?
4.串口案例一串口通訊_hal庫輪詢方式
我們有usart1配置。
我們反正還得需要配,這個時候我們可以不管他,直接去左邊框欄中點點點。圖形化配置的精髓就是方便。
還是調用hal庫簡單。
輪詢方式使用效率不是很高,中斷方式才高。
5.HAL庫中斷方式—定長數據接收
記住USART1用異步模式,要打開中斷實現
中斷方式要和回調函數結合。
接收定長數據,會和之前接收的數據結合分析
6.HAL庫中斷方式--變長數據接收
接收變長數據,size是可接收的字長上限。
她的回調不一樣,是下面這個。在函數面前加void,我忘了加,編譯出錯。
先檢查是什么模塊
7.重定向printf—寄存器方式
用printf輸出調試信息,打印到屏幕,沒有屏幕也可重定向printf,把數據打印到串口,從而在電腦端接收調試信息,這是一種有效調試手段。
printf大法對任何語言都是有用的。
printf的底層函數:fputc
把字符一個個發到控制臺文件里。?
重寫也在usart.c里,記得引入<stdio.h>
8.重定向——hal
usart.c里
在main函數來隨便打印。