usart.c
#include "sys.h"
#include "usart.h"
#include "led.h"
//
#include "stdlib.h"
#include "stdarg.h"
#include "stdio.h"
//加入以下代碼,支持printf函數,而不需要選擇use MicroLIB
#if 1#pragma import(__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;}// printf("HEllo") printf("i=%d\r\n",i) ;
#endif//串口1中斷服務程序
//注意,讀取USARTx->SR能避免莫名其妙的錯誤
char USART1_RX_BUF[USART1_REC_LEN]; //接收緩沖,最大USART_REC_LEN個字節.
//接收狀態
//bit15, 接收完成標志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字節數目
u16 USART_RX_STA=0; //接收狀態標記
u16 USART1_Rec_Byte_Length=0;//接收長度,最大是200,在接收數組空間范圍內?
u8 USART1_Rec_Frame_Flag=0;//接收完整一幀標記//初始化IO 串口1
//bound:波特率
void uart1_init(u32 baudRate)
{//GPIO端口設置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA時鐘DISABLERCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時鐘//串口1對應引腳復用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9復用為USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10復用為USART1//USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9與GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復用輸出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10//USART1 初始化設置USART_InitStructure.USART_BaudRate = baudRate;//波特率設置USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式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); //初始化串口1USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟相關中斷,接收一個字節,就發生中斷
}void USART1_IRQHandler(void) //串口1中斷服務程序
{u8 Res;//接收中斷(接收到的數據必須是0x0a結尾)if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {Res =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的數據USART1_RX_BUF[USART1_Rec_Byte_Length]=Res;//將數據放到緩沖區中if(USART1_RX_BUF[USART1_Rec_Byte_Length]==DIY_END_CODE) //如果接收到的最后的數據是約定好的幀尾{if(USART1_RX_BUF[USART1_Rec_Byte_Length-1]==DIY_END_CODE_Before){USART1_Rec_Frame_Flag=1;//接收標記等于1,在哪里清0?在判斷里面清0}//USART1_Rec_Byte_Length=0;//長度清零,給下次使用}else{USART1_Rec_Byte_Length++;//遞增座位號,不斷放到數組中if(USART1_Rec_Byte_Length>USART1_REC_LEN-1) USART1_Rec_Byte_Length=0;}} }
void Clear_Uart1_RecBuf(void)//清空接收緩沖區
{char *p;u8 i;p=USART1_RX_BUF;for(i=0;i<USART1_REC_LEN;i++){*p++=0;}USART1_Rec_Byte_Length=0;USART1_Rec_Frame_Flag=0;
}//#include "stdlib.h"
//#include "stdarg.h"
//#include "stdio.h"
//#include "string.h" //str函數
//帶不定長度參數的函數
u8 Judge_Usart1_Response(char* fmt,...)
{char p[30];va_list ap;//如果串口1沒接收到一幀數據,那么返回0,結束本函數if(!USART1_Rec_Frame_Flag) return 0;//如果接收到一幀數據,到下面將需要判斷的數據數據復制到p數組中va_start(ap,fmt);vsprintf((char*)p,fmt,ap);va_end(ap); //結束ap指針,必須結束//用strstr函數,將接收到的字符串和我們的數據進行對比,如果沒有相等的那么返回0并結束函數,否則返回1說明判斷有效if(strstr((char*)USART1_RX_BUF,p)==NULL) return 0;else return 1;
}//獲取指定格式字符串的部分數據
//x=12,y=12.5 \r\n
u8 Get_Usart1_Data(int *x,float *y)
{int xtemp;float ytemp;if(!USART1_Rec_Frame_Flag) return 0;//第一個字符,第二個字符。else if(USART1_RX_BUF[0]=='x' && USART1_RX_BUF[1]=='='){sscanf((const char *)USART1_RX_BUF,"x=%d,y=%f",&xtemp,&ytemp);*x=(int)xtemp;*y=(float)ytemp;return 1;}else return 0;
}
//https://www.cnblogs.com/zhanxiaohong0303/p/zz_2020_10_1.html//*******************************
//int main(void)
//{
//
// u8 t;
// u8 len;
// u16 times=0;
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
// delay_init(168); //延時初始化
// uart_init(115200); //串口初始化波特率為115200
// LED_Init(); //初始化與LED連接的硬件接口
// while(1)
// {
// if(USART_RX_STA&0x8000)
// {
// len=USART_RX_STA&0x3fff;//得到此次接收到的數據長度
// printf("\r\n您發送的消息為:\r\n");
// for(t=0;t<len;t++)
// {
// USART_SendData(USART1, USART_RX_BUF[t]); //向串口1發送數據
// while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待發送結束
// }
// printf("\r\n\r\n");//插入換行
// USART_RX_STA=0;
// }else
// {
// times++;
// if(times%5000==0)
// {
// printf("\r\nALIENTEK 探索者STM32F407開發板 串口實驗\r\n");
// printf("正點原子@ALIENTEK\r\n\r\n\r\n");
// }
// if(times%200==0)printf("請輸入數據,以回車鍵結束\r\n");
// if(times%30==0)LED0=!LED0;//閃爍LED,提示系統正在運行.
// delay_ms(10);
// }
// }
//}//void Clear_Openmv_Rxbuff(void)
//{
// u8 *p,i;
// p=openmv_rx_data;
// for(i=0;i<Rx_Length;i++)
// {
// *p++=0;
// }
// length=0;
// rx_flag=0;
//}//u8 Judge_Openmv_Response(char* fmt,...)
//{
// char p[30];
// if(!rx_flag) return 0;
// va_list ap;
// va_start(ap,fmt);
// vsprintf((char*)p,fmt,ap);
// va_end(ap);
// if(strstr((char*)openmv_rx_data,p)==NULL) return 0;
// else return 1;
//}// if(Judge_Openmv_Response("OK"))
// {
// Clear_Openmv_Rxbuff();
// LCD_ShowString(0,16,"OK");
// }
usart.h
#ifndef __USART_H
#define __USART_H#include "stdio.h"
#include "stm32f4xx_conf.h"
#include "sys.h" //********************************************************************************
#define USART1_REC_LEN 256 //定義最大接收字節數 200
#define DIY_END_CODE_Before 0x0D //每次發送的幀尾\n
#define DIY_END_CODE 0x0A //每次發送的幀尾\nextern char USART1_RX_BUF[USART1_REC_LEN]; //接收緩沖,最大USART_REC_LEN個字節.末字節為換行符
extern u16 USART1_RX_STA; //接收狀態標記 extern u16 USART1_Rec_Byte_Length;//接收長度,最大是200,在接收數組空間范圍內?
extern u8 USART1_Rec_Frame_Flag;//接收完整一幀標記=0,沒接收完,=1接收完void uart1_init(u32 baudRate);//設置串口1的波特率,以及初始化
void Clear_Uart1_RecBuf(void);//清空接收緩沖區
u8 Judge_Usart1_Response(char* fmt,...);//判斷串口1接受到的字符串,比對
//if(Judge_Usart1_Response("OK"))只要存在OK連續兩個就行,分大小寫
//uyyOKoo
//https://www.cnblogs.com/zhanxiaohong0303/p/zz_2020_10_1.html
//將按照指定格式接收的數據賦值
u8 Get_Usart1_Data(int *x,float *y);u8 Get_Usart1_Data2(float *x,float *y);#endif