實驗目的: 實現利用串口1不停的打印一個信息到電腦上,同時接收從串口發過來的數據,把發送過來的數據直接送回給電腦。 實驗平臺: 基于STM32F103C8T6的彩屏開發板 硬件接口: 注意:因為我的開發板上的串口和LED共用了PA9和PA10,所以在使用USART1時務必屏蔽LED,不然兩者會互相影響而導致實現現象無法呈現。 相關寄存器: 1,串口時鐘使能。串口作為STM32 的一個外設,其時鐘由外設時鐘使能寄存器控制,這 里我們使用的串口1 是在APB2ENR 寄存器的第14 位。 2,串口復位。串口1 的復位是通過配置APB2RSTR 寄存器的第14位來實現的。。通過向該位寫1來復位串口1,寫0 結束復位。 3,串口波特率設置。每個串口都有一個自己獨立的波特率寄存器USART_BRR 波特率的計算,STM32 的串口波特率計算公式如下: 
上式中, 是給串口的時鐘(PCLK1 用于USART2、3、4、5,PCLK2 用于USART1);USARTDIV是一個無符號定點數。我們只要得到USARTDIV 的值,就可以得到串口波特率寄存器USART1->BRR的值。 4,串口控制。STM32 的每個串口都有3 個控制寄存器USART_CR1~3,串口的很多配置 都是通過這3 個寄存器來設置的 5,數據發送與接收。STM32 的發送與接收是通過數據寄存器USART_DR 來實現的,這是 一個雙寄存器,包含了TDR 和RDR。 6,串口狀態。串口的狀態可以通過狀態寄存器USART_SR 讀取。 (注:詳細的介紹使用請參考ST公司的數據手冊) 程序設計: (注:本人的usart.c usart.h delay.cdelay.h sys.c sys.h是引用網上一位網友整理的) usart.h #ifndef __USART_H #define __USART_H #include<stm32f10x_lib.h> #include"stdio.h" extern u8USART_RX_BUF[64]; //接收緩沖,最大63個字節.末字節為換行符 extern u8USART_RX_STA; //接收狀態標記 //如果想串口中斷接收,請不要注釋以下宏定義 #define EN_USART1_RX //使能串口1接收 void uart_init(u32 pclk2,u32 bound); #endif usart.c #include "sys.h" #include "usart.h" //加入以下代碼,支持printf函數,而不需要選擇useMicroLIB #if 1 #pragmaimport(__use_no_semihosting) //標準庫需要的支持函數 struct __FILE { int handle; }; FILE__stdout; //定義_sys_exit()以避免使用半主機模式 _sys_exit(int x) { x = x; } //重定義fputc函數 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//循環發送,直到發送完畢 USART1->DR = (u8)ch; return ch; } #endif //end ////////////////////////////////////////////////////////////////// #ifdefEN_USART1_RX //如果使能了接收 //串口1中斷服務程序 //注意,讀取USARTx->SR能避免莫名其妙的錯誤 u8USART_RX_BUF[64]; //接收緩沖,最大64個字節. //接收狀態 //bit7,接收完成標志 //bit6,接收到0x0d //bit5~0,接收到的有效字節數目 u8USART_RX_STA=0; //接收狀態標記 void USART1_IRQHandler(void) { u8 res; if(USART1->SR&(1<<5))//接收到數據 { res=USART1->DR; if((USART_RX_STA&0x80)==0)//接收未完成 { if(USART_RX_STA&0x40)//接收到了0x0d { if(res!=0x0a) USART_RX_STA=0;//接收錯誤,重新開始 else USART_RX_STA|=0x80; //接收完成了 }else //還沒收到0X0D { if(res==0x0d) USART_RX_STA|=0x40; else { USART_RX_BUF[USART_RX_STA&0X3F]=res; USART_RX_STA++; if(USART_RX_STA>63)USART_RX_STA=0;//接收數據錯誤,重新開始接收 } } } } } #endif //該函數的重點就是判斷接收是否完成,通過檢測是否收到0X0D、0X0A 的連續2 個字節//(0X0D 后跟0X0A表示回車鍵)來檢測是否結束。當檢測到這個結束序列之后,就會置//位USART_RX_STA的最高為來標記已經收到了一次數據。之后等待外部函數清空該位//之后才開始第二次接收。所接收的數據全部存放在USART_RX_BUF里面,一次接收數//據不能超過64個字節,否則被丟棄。 //初始化IO 串口1 //pclk2:PCLK2時鐘頻率(Mhz) //bound:波特率 //CHECK OK //091209 void uart_init(u32 pclk2,u32 bound) { float temp; u16 mantissa; u16fraction; temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV mantissa=temp; //得到整數部分 fraction=(temp-mantissa)*16;//得到小數部分 mantissa<<=4; mantissa+=fraction; RCC->APB2ENR|=1<<2; //使能PORTA口時鐘 RCC->APB2ENR|=1<<14; //使能串口時鐘 GPIOA->CRH&=0XFFFFF00F; GPIOA->CRH|=0X000008B0;//IO狀態設置 RCC->APB2RSTR|=1<<14; //復位串口1 RCC->APB2RSTR&=~(1<<14);//停止復位 //波特率設置 USART1->BRR=mantissa; // 波特率設置 USART1->CR1|=0X200C; //1位停止,無校驗位. #ifdefEN_USART1_RX //如果使能了接收 //使能接收中斷 USART1->CR1|=1<<8; //PE中斷使能 USART1->CR1|=1<<5; //接收緩沖區非空中斷使能 MY_NVIC_Init(3,3,USART1_IRQChannel,2);//組2,最低優先級 #endif } 主函數 #include<stm32f10x_lib.h> #include"common.h" int main(void) { u8 t; u8 len; u16times=0; Stm32_Clock_Init(9);//系統時鐘設置 delay_init(72); //延時初始化 uart_init(72,9600);//串口初始化為9600 while(1) { if(USART_RX_STA&0x80) { len=USART_RX_STA&0x3f;//得到此次接收到的數據長度 printf("\n您發送的消息為:\n"); for(t=0;t<len;t++) { USART1->DR=USART_RX_BUF[t]; while((USART1->SR&0X40)==0);//等待發送結束 } printf("\n\n");//插入換行 USART_RX_STA=0; }else { times++; if(timesP00==0) { printf("\n 簡單的串口實驗\n"); } if(times 0==0)printf("請輸入數據,以回車鍵結束\n"); delay_ms(10); } } } 實驗現象:
|