在此聲明一下所有代碼均為 杜洋工作室 的不允許復(fù)制,轉(zhuǎn)發(fā)等,本人只是在此程序上進(jìn)行理解和注釋。
接著上一個(gè)筆記,上一個(gè)是用按鈕對(duì)LED燈的點(diǎn)亮,接下來研究一下串口的基本使用。在洋桃開發(fā)板上進(jìn)行用usart通信,對(duì)小電燈的控制。
本次就不講LED燈的控制說明,如果不懂的話可以看我上一個(gè)筆記:https://blog.csdn.net/qq_40546576/article/details/98090105
我給我自己出了一個(gè)小題目,結(jié)合上兩次的筆記內(nèi)容
可以讓按鈕和電腦鍵盤進(jìn)行控制小燈
每次都發(fā)會(huì)終端小燈狀態(tài)
電腦終端可以顯示是什么輸入控制;
在主要內(nèi)容之前,我們添加按鍵消抖程序,寫入在自己編寫的key.c文件中,并且需要在key.h文件中聲明一下u8 KEY_IN(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);去抖函數(shù)函數(shù)。這樣子就不要在主函數(shù)中編寫去抖函數(shù)了。
u8 KEY_IN(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)//按鍵軟件去抖{ u8 i=0; //聲明一個(gè)變量,0表示沒有按鍵按下,1表示按鍵按下 if(!GPIO_ReadInputDataBit(GPIOx, GPIO_Pin))//讀是否有按鍵按下 { delay_ms(20); //延時(shí)1毫秒 if(!GPIO_ReadInputDataBit(GPIOx, GPIO_Pin))//再次確認(rèn)是否有按鍵按下 { i=1;//設(shè)置按鍵按下變量為1 } } return i;//函數(shù)返回按鍵狀態(tài)變量 }
首先我們要編寫需要用到文件,usart.c和usart.h,這兩個(gè)名字沒有強(qiáng)制要求
這里順便聲明了usart2,usart3的相關(guān)變量
#ifndef __USART_H#define __USART_H#include <stdarg.h>#include <stdlib.h>#include <string.h>#include "stdio.h" #include "sys.h" #define USART_n USART1 //定義使用printf函數(shù)的串口,其他串口要使用USART_printf專用函數(shù)發(fā)送#define USART1_REC_LEN 200 //定義USART1最大接收字節(jié)數(shù)#define USART2_REC_LEN 200 //定義USART2最大接收字節(jié)數(shù)#define USART3_REC_LEN 200 //定義USART3最大接收字節(jié)數(shù)//不使用某個(gè)串口時(shí)要禁止此串口,以減少編譯量#define EN_USART1 1 //使能(1)/禁止(0)串口1#define EN_USART2 0 //使能(1)/禁止(0)串口2#define EN_USART3 0 //使能(1)/禁止(0)串口3 extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符 extern u8 USART2_RX_BUF[USART2_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符extern u8 USART3_RX_BUF[USART3_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符 extern u16 USART1_RX_STA; //接收狀態(tài)標(biāo)記 extern u16 USART2_RX_STA; //接收狀態(tài)標(biāo)記 extern u16 USART3_RX_STA; //接收狀態(tài)標(biāo)記 //函數(shù)聲明void USART1_Init(u32 bound);//串口1初始化并啟動(dòng)void USART2_Init(u32 bound);//串口2初始化并啟動(dòng)void USART3_Init(u32 bound);//串口3初始化并啟動(dòng)void USART1_printf(char* fmt,...); //串口1的專用printf函數(shù)void USART2_printf(char* fmt,...); //串口2的專用printf函數(shù)void USART3_printf(char* fmt,...); //串口3的專用printf函數(shù)#endif
一般編寫的時(shí)候我們主要編寫中斷服務(wù)程序內(nèi)容就可以,大多數(shù)東西不要改變,注意是否開啟中斷
#include "sys.h"#include "usart.h" //使UASRT串口可用printf函數(shù)發(fā)送//在usart.h文件里可更換使用printf函數(shù)的串口號(hào) #if 1#pragma import(__use_no_semihosting) //標(biāo)準(zhǔn)庫需要的支持函數(shù) struct __FILE { int handle; }; FILE __stdout; //定義_sys_exit()以避免使用半主機(jī)模式 _sys_exit(int x){ x = x; } //重定義fputc函數(shù) int fputc(int ch, FILE *f){ while((USART_n->SR&0X40)==0);//循環(huán)發(fā)送,直到發(fā)送完畢 USART_n->DR = (u8) ch; return ch;}#endif /*USART1串口相關(guān)程序*/ #if EN_USART1 //USART1使用與屏蔽選擇u8 USART1_RX_BUF[USART1_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié).//接收狀態(tài)//bit15, 接收完成標(biāo)志//bit14, 接收到0x0d//bit13~0, 接收到的有效字節(jié)數(shù)目u16 USART1_RX_STA=0; //接收狀態(tài)標(biāo)記 /*USART1專用的printf函數(shù)當(dāng)同時(shí)開啟2個(gè)以上串口時(shí),printf函數(shù)只能用于其中之一,其他串口要自創(chuàng)獨(dú)立的printf函數(shù)調(diào)用方法:USART1_printf("123"); //向USART2發(fā)送字符123*/void USART1_printf (char *fmt, ...){ char buffer[USART1_REC_LEN+1]; // 數(shù)據(jù)長(zhǎng)度 u8 i = 0; va_list arg_ptr; va_start(arg_ptr, fmt); vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr); while ((i < USART1_REC_LEN) && (i < strlen(buffer))){ USART_SendData(USART1, (u8) buffer[i++]); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); } va_end(arg_ptr);}void USART1_Init(u32 bound){ //串口1初始化并啟動(dòng) //GPIO端口設(shè)置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時(shí)鐘 //USART1_TX PA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出 GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX PA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入 GPIO_Init(GPIOA, &GPIO_InitStructure); //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器 //USART 初始化設(shè)置 USART_InitStructure.USART_BaudRate = bound;//一般設(shè)置為9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長(zhǎng)為8位數(shù)據(jù)格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗(yàn)位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據(jù)流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式 USART_Init(USART1, &USART_InitStructure); //初始化串口 USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//開啟ENABLE/關(guān)閉DISABLE中斷 USART_Cmd(USART1, ENABLE); //使能串口 }//串口1中斷服務(wù)程序(固定的函數(shù)名不能修改)void USART1_IRQHandler(void){ u8 a; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ //接收中斷(接收到的數(shù)據(jù)必須是0x0d 0x0a結(jié)尾) a =USART_ReceiveData(USART1);//讀取接收到的數(shù)據(jù) switch (a){ case '1': GPIO_WriteBit(LEDPORT, LED1, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED1))); //LED控制 if(GPIO_ReadOutputDataBit(LEDPORT, LED1)){ printf("電腦鍵盤1按下 \t LED1 燈亮 \n\r"); }else{ printf("電腦鍵盤1按下 \t LED1 燈滅 \n\r"); }; break; case '2': GPIO_WriteBit(LEDPORT, LED2, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED2))); //蜂鳴一聲 if(GPIO_ReadOutputDataBit(LEDPORT, LED2)){ printf("電腦鍵盤2按下 \t LED1 燈亮 \n\r"); }else{ printf("電腦鍵盤2按下 \t LED1 燈滅 \n\r"); }; break; default: break; } } } #endif
編寫注意點(diǎn)
相關(guān)的頭文件導(dǎo)入
相關(guān)驅(qū)動(dòng)函數(shù)的初始化
因?yàn)橛玫臅r(shí)USART串口進(jìn)行通信,我們選擇中斷還是查詢
查詢方式接收標(biāo)志函數(shù)主要用到USART_GetFlagStatus(USART1,USART_FLAG_RXNE)
中斷方式接收標(biāo)志函數(shù)主要用到
USART_GetITStatus(USART1, USART_IT_RXNE)
接收數(shù)據(jù)函數(shù)
USART_ReceiveData(USART1)
#include "stm32f10x.h" //STM32頭文件#include "sys.h"#include "delay.h"#include "led.h"#include "delay.h"#include "key.h"#include "usart.h"int main (void){//主程序 u8 a; //查詢時(shí)的接受數(shù)據(jù)變量,如果用中斷就可以去掉,編譯時(shí)就沒有警告! RCC_Configuration(); //時(shí)鐘設(shè)置 LED_Init(); KEY_Init();//按鍵初始化 USART1_Init(115200); //串口初始化,參數(shù)中寫波特率 while(1) // USART串口研究 { if(KEY_IN(KEYPORT, KEY1)) //判斷key1是否按下 { GPIO_WriteBit(LEDPORT, LED1, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED1))); //改變LED1燈的狀態(tài) if(GPIO_ReadOutputDataBit(LEDPORT, LED1)){ //用輸出函數(shù)把相應(yīng)的狀態(tài)發(fā)給電腦 printf("KEY1按下 \t LED1 燈亮 \n\r"); }else{ printf("KEY1按下 \t LED1 燈滅 \n\r"); } while(!GPIO_ReadInputDataBit(KEYPORT, KEY1));//等待按鍵松開 } if(KEY_IN(KEYPORT, KEY2))//判斷key2是否按下 { GPIO_WriteBit(LEDPORT, LED2, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED2))); //改變LED2燈的狀態(tài) if(GPIO_ReadOutputDataBit(LEDPORT, LED2)){ //用輸出函數(shù)把相應(yīng)的狀態(tài)發(fā)給電腦 printf("KEY2按下 \t LED2 燈亮 \n\r"); }else{ printf("KEY2按下 \t LED2 燈滅 \n\r"); } while(!GPIO_ReadInputDataBit(KEYPORT, KEY2));//等待按鍵松開 } //查詢方式接收 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET){ //查詢串口待處理標(biāo)志位 a =USART_ReceiveData(USART1);//讀取接收到的數(shù)據(jù) switch (a){ case '1': //判斷電腦鍵盤1是否按下 GPIO_WriteBit(LEDPORT, LED1, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED1))); //LED控制 if(GPIO_ReadOutputDataBit(LEDPORT, LED1)){ printf("電腦鍵盤1按下 \t LED1 燈亮 \n\r"); }else{ printf("電腦鍵盤1按下 \t LED1 燈滅 \n\r"); }; break; case '2': //判斷電腦鍵盤2是否按下 GPIO_WriteBit(LEDPORT, LED2, (BitAction) (!GPIO_ReadOutputDataBit(LEDPORT, LED2))); //LED控制 if(GPIO_ReadOutputDataBit(LEDPORT, LED2)){ printf("電腦鍵盤2按下 \t LED1 燈亮 \n\r"); }else{ printf("電腦鍵盤2按下 \t LED1 燈滅 \n\r"); };// break; default:printf("電腦鍵盤輸入有誤! \n\r"); //識(shí)別電腦發(fā)來數(shù)據(jù)有誤,發(fā)給電腦提示 break; } } }}
自我總結(jié)
/**研究注意點(diǎn)
1-GPIO的控制越來越熟練了
2-用USART串口時(shí),一定要知道時(shí)用中斷,還是查詢,并且在USART初始化中給出明確的狀態(tài)
3-本次中斷服務(wù)程序與查詢服務(wù)程序相似
4-洋桃已經(jīng)把STM32輸出函數(shù)已經(jīng)寫好不需要修改和編寫
5-但是需要編寫接收函數(shù),即服務(wù)程序(中斷還是查詢)
參考來源:
杜洋工作室 www.DoYoung.net
洋桃電子 www.DoYoung.net/YT
STM32庫開發(fā)實(shí)戰(zhàn)指南 基于STM32F103(第二版)
聯(lián)系客服