正文
要进入按键输入,我们必须先明确,按键连在哪一个GPIO口,通过开发手册,如下
因此,我们可以在蜂鸣器和跑马灯的基础上,完成该实验。
按键输入
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "beep.h"
#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP)
//#define KEY0 PEin(4) PE4
//#define KEY1 PEin(3) PE3
//#define WK_UP PAin(0) PA0,作用跟上面一样,可替换
#define KEY0_PRES 1 //KEY0按下
#define KEY1_PRES 2 //KEY1按下
#define WKUP_PRES 3 //KEY_UP按下(即WK_UP/KEY_UP)
int main(void)
{
vu8 key=0;
delay_init(); //延时函数初始化
LED_Init();
BEEP_Init();
KEY_Init(); //初始化与按键连接的硬件接口
LED0=0; //先点亮红灯
while(1)
{
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case WKUP_PRES: //控制蜂鸣器
BEEP=!BEEP;
break;
case KEY1_PRES: //控制LED1翻转
LED1=!LED1;
break;
case KEY0_PRES: //同时控制LED0,LED1翻转
LED0=!LED0;
LED1=!LED1;
break;
}
}else delay_ms(10);
}
}
void KEY_Init(void) //IO³õʼ»¯
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//ʹÄÜPORTA,PORTEʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOE, &GPIO_InitStructure);//
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//0,没有按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//响应优先级 KEY0>KEY1>KEY_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键松开
if(mode)key_up=1;
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);消抖
key_up=0;
if(KEY0==0)return KEY0_PRES; //1
else if(KEY1==0)return KEY1_PRES; //2
else if(WK_UP==1)return WKUP_PRES; //3
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;//无按键按下
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
以上,我们设置一个按键是上拉输入,一个按键是下拉输入,那有什么区别呢?
1、上拉输入:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!强弱只是上拉电阻的阻值不同,没有什么严格区分。
2、下拉输入:就是把电压拉低,拉到GND。与上拉原理相似。
对于KEY0和KEY1,通过上拉电阻,把引脚的电平嵌位在高电平,当按键按下时,按引脚电平转变成低电平。而对于WK_UP,因为是高电平触发,因此我们把它拉低。
串口实验
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
int main(void)
{
u16 t;
u16 len;
u16 times=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1)
{
//接收状态
//bit15 接收完成标记
//bit14£¬ 接收到oxod
//bit13~0 接收到的有效字节数目
//u16 USART_RX_STA=0; //接收状态标记
if(USART_RX_STA&0x8000) //如果接受到数据...
{
len=USART_RX_STA&0x3fff;//得到数据长度
printf("rn你发送的消息为:rnrn");
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
printf("rnrn");//插入换行
USART_RX_STA=0;
}else
{
times++;
if(times%200==0)printf("请输入数据n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行
delay_ms(10);
}
}
}
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.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; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
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); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
运行结果如下:
关于串口
ALIENTEK精英STM32开发板所使用的STM32F103ZET6最多可提供5路串口,有分数波特率发生器,支持同步单线通信和半双工单线通讯,支持LIN,支持调制解调器操作,智能卡协议和IrDA SIR ENDEC规范,具有DMA等。
void uart_init(u32 bound)函数是串口1初始化函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA,ENABLE);
//使用USART1,GPIOA,该口具有复用功能
接下来,我们要初始化相应的GPIO端口为特定的状态,如下:
所以需要配置TX(PA9)设置为推挽复用输出模式,将RX(PA10)设置为浮空输入模式
//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; //复用推挽输出
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的中断初始化,设置抢占优先级值和子优先级的值:
//Usart1 NVIC 中断配置 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器
以上涉及到的中断知识,将在下一次实验讲
USART1_IRQHandler函数
这是串口1的中断响应函数,当串口1发生了相应的中断后,就会跳到该函数执行。中断相应函数的名字不能随便定义,需要遵循MDK定义的函数名,这在startup_stm32f10x_hd.s文件中可以找到。
if (USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
//判断是否接收中断,如果是串口接收中断,则读取串口接收到的数据。
RES = USART_ReceiveData(USART1); //(USART1->DR); 读取接收的数据
读取接收的数据 既然读取到了数据,那么我们就需要对数据进行分析。
一个接收状态寄存器USART_RX_STA(此寄存器其实就是一个全局变量),定义如下:
当接收到从电脑发过来的数据,把接收到的数据保存在USART_RX_BUF中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车由两个字节组成:0x0D和0x0A)的第一个字节0X0D时,计数器不再增加,等待0x0A的到来,如果0x0A没有到来,则认为这次接收失败,重新开始下一次的接收。
数据的发送和接收
STM32的发送与接收是通过数据寄存器USART_DR来实现的,这是一个双寄存器,包含了TDR和RDR。当向该寄存器写数据的时候,串口就会自动发送。当收到该数据的时候,也是存在该寄存器内.
void USART_SendData(USART_TypeDef* USARTx,uint16_t Data);
//通过该函数向串口寄存器USART_dR写入一个数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//通过该函数读取串口接收到的数据
总结
通过以上,我学会了基本的按键输入与串口实验,下一次学习外部中断和独立看门狗的实验。
正文
要进入按键输入,我们必须先明确,按键连在哪一个GPIO口,通过开发手册,如下
因此,我们可以在蜂鸣器和跑马灯的基础上,完成该实验。
按键输入
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "beep.h"
#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP)
//#define KEY0 PEin(4) PE4
//#define KEY1 PEin(3) PE3
//#define WK_UP PAin(0) PA0,作用跟上面一样,可替换
#define KEY0_PRES 1 //KEY0按下
#define KEY1_PRES 2 //KEY1按下
#define WKUP_PRES 3 //KEY_UP按下(即WK_UP/KEY_UP)
int main(void)
{
vu8 key=0;
delay_init(); //延时函数初始化
LED_Init();
BEEP_Init();
KEY_Init(); //初始化与按键连接的硬件接口
LED0=0; //先点亮红灯
while(1)
{
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case WKUP_PRES: //控制蜂鸣器
BEEP=!BEEP;
break;
case KEY1_PRES: //控制LED1翻转
LED1=!LED1;
break;
case KEY0_PRES: //同时控制LED0,LED1翻转
LED0=!LED0;
LED1=!LED1;
break;
}
}else delay_ms(10);
}
}
void KEY_Init(void) //IO³õʼ»¯
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//ʹÄÜPORTA,PORTEʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOE, &GPIO_InitStructure);//
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//0,没有按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//响应优先级 KEY0>KEY1>KEY_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键松开
if(mode)key_up=1;
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);消抖
key_up=0;
if(KEY0==0)return KEY0_PRES; //1
else if(KEY1==0)return KEY1_PRES; //2
else if(WK_UP==1)return WKUP_PRES; //3
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;//无按键按下
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
以上,我们设置一个按键是上拉输入,一个按键是下拉输入,那有什么区别呢?
1、上拉输入:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!强弱只是上拉电阻的阻值不同,没有什么严格区分。
2、下拉输入:就是把电压拉低,拉到GND。与上拉原理相似。
对于KEY0和KEY1,通过上拉电阻,把引脚的电平嵌位在高电平,当按键按下时,按引脚电平转变成低电平。而对于WK_UP,因为是高电平触发,因此我们把它拉低。
串口实验
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
int main(void)
{
u16 t;
u16 len;
u16 times=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1)
{
//接收状态
//bit15 接收完成标记
//bit14£¬ 接收到oxod
//bit13~0 接收到的有效字节数目
//u16 USART_RX_STA=0; //接收状态标记
if(USART_RX_STA&0x8000) //如果接受到数据...
{
len=USART_RX_STA&0x3fff;//得到数据长度
printf("rn你发送的消息为:rnrn");
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
printf("rnrn");//插入换行
USART_RX_STA=0;
}else
{
times++;
if(times%200==0)printf("请输入数据n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行
delay_ms(10);
}
}
}
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.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; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
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); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
运行结果如下:
关于串口
ALIENTEK精英STM32开发板所使用的STM32F103ZET6最多可提供5路串口,有分数波特率发生器,支持同步单线通信和半双工单线通讯,支持LIN,支持调制解调器操作,智能卡协议和IrDA SIR ENDEC规范,具有DMA等。
void uart_init(u32 bound)函数是串口1初始化函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA,ENABLE);
//使用USART1,GPIOA,该口具有复用功能
接下来,我们要初始化相应的GPIO端口为特定的状态,如下:
所以需要配置TX(PA9)设置为推挽复用输出模式,将RX(PA10)设置为浮空输入模式
//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; //复用推挽输出
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的中断初始化,设置抢占优先级值和子优先级的值:
//Usart1 NVIC 中断配置 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器
以上涉及到的中断知识,将在下一次实验讲
USART1_IRQHandler函数
这是串口1的中断响应函数,当串口1发生了相应的中断后,就会跳到该函数执行。中断相应函数的名字不能随便定义,需要遵循MDK定义的函数名,这在startup_stm32f10x_hd.s文件中可以找到。
if (USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
//判断是否接收中断,如果是串口接收中断,则读取串口接收到的数据。
RES = USART_ReceiveData(USART1); //(USART1->DR); 读取接收的数据
读取接收的数据 既然读取到了数据,那么我们就需要对数据进行分析。
一个接收状态寄存器USART_RX_STA(此寄存器其实就是一个全局变量),定义如下:
当接收到从电脑发过来的数据,把接收到的数据保存在USART_RX_BUF中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车由两个字节组成:0x0D和0x0A)的第一个字节0X0D时,计数器不再增加,等待0x0A的到来,如果0x0A没有到来,则认为这次接收失败,重新开始下一次的接收。
数据的发送和接收
STM32的发送与接收是通过数据寄存器USART_DR来实现的,这是一个双寄存器,包含了TDR和RDR。当向该寄存器写数据的时候,串口就会自动发送。当收到该数据的时候,也是存在该寄存器内.
void USART_SendData(USART_TypeDef* USARTx,uint16_t Data);
//通过该函数向串口寄存器USART_dR写入一个数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//通过该函数读取串口接收到的数据
总结
通过以上,我学会了基本的按键输入与串口实验,下一次学习外部中断和独立看门狗的实验。
举报