一.按键
这些按键在没有被按下的时候,GPIO 引脚的输入状态为低电平。(则应该设置成下拉模式)推挽输出以及速出速率都不用要了。这里已经硬件消抖了,软件就不用了。
按键的初始化:
void KEY_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;//变量第一要在第一位
RCC_AHB1PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);//开启时钟
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd= GPIO_PuPd_DOWN;//下拉
GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_PIN;
GPIO_Init(KEY2_GPIO_PORT,&GPIO_InitStruct);
}
按键扫描程序
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
else
{
return KEY_OFF;
}
GPIO_ReadInputDataBit()是检测GPIO的函数,可以直接调用,用读取返回的键值来作为判断依据。
头文件:
主函数调用Key_Scan进行读取再判断键值,进行动作。
2.系统时钟树
二.中断
STM32 每个外设都可以产生中断(异常)。
有关具体的系统异常和外部中断可在标准库文件stm32f4xx.h 这个头文件查询到,在IRQn_Type 这个结构体里面包含了F4 系列全部的异常声明。
先了解一下NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对Cortex-M4 内核里面的NVIC 进行裁剪,把不需要的
部分去掉,所以说STM32 的NVIC 是Cortex-M4 的NVIC 的一个子集。
固件库文件core_cm4.h 的最后,还提供了NVIC 的一些函数,这些函数遵循CMSI 规则,只要是Cortex-M4 的处理器都可以使用。里面是NVIC的一些库函数。
在misc.h里面罗列了有关中断NVIC的函数。
中断编程:
1)NVIC_IROChannel:第一个中断源的设置可参考stm32f4xx.h 头文件里面的IRQn_Type 结构体定义,这个结构体包含了所有的中断源。,不同的中断中断源不一样,且不可写错,即使写错了程序不会报错,只会导致不想要中断。
2)NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定。
3)NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定。
4)NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的是NVIC_ISER 和NVIC_ICER 这两个寄存器。
那么开始编写中断服务函数
在启动文件startup_stm32f429_439xx.s 中我们预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,中断服务函数我们统一写在stm32f4xx_it.c 这个库文件中。
EXTI外部中断
外部中断/事件控制器(EXTI)管理了控制器的23 个中断/事件线。
每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件
上就有所不同。红色虚线指示的电路流程。它是一个产生中断的线路,最终信号流入到NVIC 控制器内。(3或门,4与门)
产生中断线路目的是把输入信号输入到NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
另外,EXTI 是在APB2 总线上的,在编程时候需要注意到这点。
编程:
外部中断初始化结构体
1)EXTI_Line:EXTI 中断/事件线选择,可选EXTI0 至EXTI22,可参考表 17-1 选择。
2) EXTI_Mode:EXTI 模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事
件(EXTI_Mode_Event)。
3) EXTI_Trigger:EXTI 边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、下
降沿触发( EXTI_Trigger_Falling) 或者上升沿和下降沿都触发
( EXTI_Trigger_Rising_Falling)。
4) EXTI_LineCmd:控制是否使能EXTI 线,可选使能EXTI 线(ENABLE)或禁用
(DISABLE)。
我们创建了两个文件:bsp_exti.c 和bsp_exti.h 文件用来存放EXTI 驱动程序及相关宏定义,中断服务函数放在stm32f4xx_it.h 文件中。(要把这个文件放到对应的外设文件里面去,反正不知道为哈我单独创了个文件夹他就找不到头文件了啊 啊啊啊啊啊!!!!比如KEY文件夹里面可以存放。可能是跟他这个EXTI的名字有关系吧,反正我在conf里面看了也没有屏蔽的头文件啊QWQ)
先对exti.h进行编写,在key.h的基础上,我们可以添加对SYSCFG_EXTI_Port_Sources\pin 的定义(跟普通GPIO是一样的)。还有外部中断线和外部中断编号。以及中断服务函数。
.h文件 通过查找该启动文件,可以发现EXTI13的中断服务函数应该是EXTI15_10_IRQHandler,而EXTI0的中断函数就是EXTI0_IRQHandler。
.C文件
首先,使用GPIO_InitTypeDef 和EXTI_InitTypeDef 结构体定义两个用于GPIO 和EXTI 初始化配置的变量。使用GPIO 之前必须开启GPIO 端口的时钟;用到EXTI 必须开启SYSCFG 时钟。
编写 EXTI_NVIC_Config(void)完成对NVIC的配置。再写EXTI_Key_Config, 调用EXTI_NVIC_Config函数完成对按键1、按键2 优先级配置并使能中断通道。
我们的目的是产生中断,执行中断服务函数,EXTI 选择中断模式,按键1 使用上升沿触发方式,并使能EXTI 线,按键2 基本上采用与按键1 相关参数配置,只是改为下降沿沿触发方式。最后再在中断服务函数里面编写文件实现。
static void EXTI_NVIC_Config(void)//NVIC配置
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC 为优先级组1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中断源:按键1 */
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
/* 配置抢占优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置中断源:按键2,其他使用上面相关配置 */
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*开启按键相关的GPIO外设时钟*/
RCC_AHB1PeriphClockCmd (KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
/* 使能 SYSCFG 时钟 ,使用GPIO 外部中断时必须使能SYSCFG 时钟*/
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_SYSCFG, ENABLE);
/* 配置 NVIC */
EXTI_NVIC_Config();
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
/* 连接 EXTI 中断源 到key1 引脚 */
SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 中断模式 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发,相当于按下按键触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*KEY2跟着设就行了*/
GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
SYSCFG_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE,KEY2_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 中断模式 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发,相当于弹起按键触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
三.系统定时器
SHPRx,其中STK 这个章节有SysTick 的简介和寄存器的详细描述。因为SysTick 是属于CM4 内核的外设,有关寄存器的定义和部分库函数都在core_cm4.h 这个头文件中实现。所以学习SysTick 的时候可以参考这两个资料,一个是文档,一个是源码。SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件core_cm4.h 中。
SysTick—系统定时器是属于CM4 内核中的一个外设,内嵌在NVIC 中。系统定时器是一个24bit 的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK 等于180M。当重装载数值寄存器的值递减到0 的时候,系统定时器就产生一次中断,以此循环往复。</font color >
用固件库编程的时候我们只需要调用库函数SysTick_Config()即可,形参ticks 用来设置重装载寄存器的值,最大不能超过重装载寄存器的值224,当重装载寄存器的值递减到0的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置系统定时器的时钟为180M,使能定时器和定时器中断,这样系统定时器就配置好了,一个库函数搞定。(core_cm4.h)
可以看到,如果定时器配置成功了会返回值0。SysTick_Config()库函数主要配置了SysTick 中的三个寄存器:LOAD、VAL 和CTRL.因为SysTick 属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级和子优先级的说法。在STM32F429 中,内核外设的中断优先级由内核SCB 这个外设的寄存器:SHPRx(x=1.2.3)来配置。
计数一次的时间TDEC=1/CLKAHB,当重装载寄存器中的值VALUELOAD 减到0 的时候,产生中断,可知中断一次的时间
TINT=VALUELOAD * TDEC 中断= VALUELOAD/CLKAHB,其中CLKAHB =180MHZ。如果设置为180,那中断一次的时间TINT=180/180M=1us。不过1us 的中断没啥意义,整个程序的重心都花在进出中断上了,根本没有时间处理其他的任务。
SysTick_Config()的形我们配置为SystemCoreClock / 100000=180M/100000=1800从刚刚分析我们知道这个形参的值最终是写到重装载寄存器LOAD 中的,从而可知我们现在把SysTick 定时器中断一次的时间TINT=1800/180M=10us。设置好中断时间TINT 后,我们可以设置一个变量t,用来记录进入中断的次数,那么变量t 乘以中断的时间TINT 就可以计算出需要定时的时间。
语法补充:这里定义了static __IO uint32_t TimingDelay这个变量:_IO 一般宏定义为volatile,表示可百读可写volatile 就是为了禁止编译器对其优化,因为对于timingdelay来说 你要设置一个初始值 但是变化是在中断中度进行的 编译器不知道 会吧这个变量优化掉。
主函数里面还是会报…\User\main.c(14): warning: #223-D: function “SysTick_Init” declared implicitly的warning到处都声明了的呜呜…
最后下载进去实现了红灯闪1s,绿灯闪10S。
四 通讯的基本概念
①1.按数据传送的方式,通讯可分为串行通讯与并行通讯
···2.全双工、半双工及单工通讯:
3.根据通讯的数据同步方式:分为同步和异步两种,可以根据通讯过程中是否有使用到时钟信号进行简单的区分。在同步通讯中,收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下双方进行协调,同步数据。
③通讯速率:
衡量通讯性能的一个非常重要的参数就是通讯速率,通常以**比特率(Bitrate)来表示,即每秒钟传输的二进制位数,**单位为比特每秒(bit/s)。容易与比特率混淆的概念是“波特率”(Baudrate),它表示每秒钟传输了多少个码元。
而码元是通讯信号调制的概念,通讯中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。如常见的通讯传输中,用0V 表示数字0,5V 表示数字1,那么一个码元可以表示两种状态0 和1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致;如果在通讯传输中,有0V、2V、4V 以及6V 分别表示二进制数00、01、10、11,那么每个码元可以表示四种状态,
即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率
的一半。
五.串口通讯协议简介
我们分别对串口通讯协议的物理层及协议层进行理解。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200408201448246.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2Y