流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)

目录

流水灯设计原理

1、基于STM32F103R6Tx的流水灯设计,先初始化管脚,编写LED、KEY按键和定时器的初始化函数。

2、按键的判断设计分为两部分:开始/停止按键和设置时间按键。
① 开始/停止按键判断
开始/停止的按键一端接地,当读到相应的传入信号为0时,即可判断该按键被按下,再进行按键次数的计数,第一次按键为开始,第二次按键为暂停,第三次按键为开始,如此循环往复。当为开始状态时,定时器使能,为停止状态时,定时器状态设置为失能。
② 设置时间按键判断
通过判断相应管脚的高低电平来确定该按键是否按下,当管脚为低电平时,该按键被按下,第一次按下每个LED灯亮起延时1秒。第二次按下延时2秒。第3次按下延时3秒,第四次按下延时1秒,如此循环往复。需要在定时器的初始化中,设置标志位,对自动重装载寄存器周期的值进行切换。

3、通过判断LED灯的四个标志位和定时器中断函数来实现流水灯的效果。初始化时,将第一个LED灯的标志位设置为1,其余LED灯设置为0。当第一次进入中断,判断,若只有第一个LED灯标志位为1,则此时第一个LED灯亮,并将第二个LED灯的标志位设置为1;当第二次进入中断,判断,若只有第二个LED灯标志位为1,则此时第二个LED灯亮,第一个LED灯灭,并将第三个LED灯的标志位设置为1;当第三次进入中断,判断,若只有第三个LED灯标志位为1,则此时第三个LED灯亮,第二个LED灯灭,同时将第四个LED灯标志位设置为1;当第四次进入中断,判断,若只有第四个LED灯标志位为1,则此时第四个LED灯亮,第三个LED灯灭,同时将四个LED灯标志位全部设置为1;当第五次进入中断,判断,若全部标志位都设置为1,则此时全部LED亮,并将另外3个LED灯设置为0,即回到了第一次进入中断的情况。

4、中断原理
中断主要分为三种中断:全局中断、外部中断和内部中断。
全局中断:在运行程序的任何一部分都可以立即执行中断服务,如果是在程序的中断才添加开放中断指令就是说有条件满足中断的时候,也只能在执行允 许中断的指令后才执行中断服务。
外部中断:屏蔽的中断,也就是说,利用中断控制器可以屏蔽这些外部设备 的中断请求。
内部中断:指因硬件出错(如突然掉电、奇偶校验错等)或运算出错(除数为 零、运算 溢出、单步中断等)所引起的中断。
此次课程设计中使用的是外部中断。
I/O 口外部中断在中断向量表中只分配了 7 个中断向量,即只可使用 7 个中断服务函数,如下表所示。

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
关于中断源的中断优先级关系,大致归纳两条基本原则:
① 低优先可被高优先级中断,高优先级不能被低优先级中断。
② 任何一种中断(不管是高级还是低级)一旦得到响应,不会再被它同等级的中断源所中断。
STM32 可支持68个中断通道,已经固定分配给相应的外部设备,每个中断 通道都具备自己的中断优先级控制字节PRI_n(8 位,但是STM32中只使用4位, 高4位有效),每4个通道的8位中断优先级控制字构成一个32位的优先级寄存 器。68个通道的优先级控制字至少构成17个32位的优先级寄存器。4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。按照这种分组,4bit一共可以分成5组,如下表所。

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
5、定时器相关原理
STM32F103系列一共有11个定时器,包括2个高级定时器(TIM1、TIM8)、4个普通定时器(TIM2-TIM5)、2个基本定时器(TIM6、TIM7)、2个看门狗定时器、1个系统嘀嗒定时器,其中8个定时器具体体现如下表。

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
基本定时器只有最基本的定时功能,基本定时器TIM6和TIM7各包含一个16 位自动装载计数器,由各自的可编程预分频器驱动。
通用定时器除了基本的定时器的功能外,还具有测量输入信号的脉冲长度 (输入捕获)或者产生输出波形(输出比较和PWM)。
高级定时器不但具有基本,通用定时器的所有的功能,还具有控制交直流电 动机所有的功能,例如它可输出6路互补带死区的信号以及拥有刹车功能等。
这8个定时器都是16位的,它们的计数器的类型除了基本定时器TIM6和TIM7都支持下面的向上,向下和中央对齐3种计数模式。
向上计数模式:从0计数到预装载值就会产生一个溢出事件,然后继续从0开始计数;
向下计数模式:从预装载值计数到0就会产生一个溢出事件,然后继续从预装载值开始计数;
中央对齐模式:计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
定时器中断实现步骤如下:
① 能定时器时钟:RCC_APB1PeriphClockCmd( );
② 初始化定时器,配置ARR,PSC:TIM_TimeBaseInit( );
③ 开启定时器中断,配置NVIC:
void TIM_ITConfig( );
NVIC_Init( );
④ 使能定时器:TIM_Cmd( );
⑤ 编写中断服务函数:TIMx_IRQHandler( );
Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk(其中Tclk为PSC时钟也就是定时器还未分频时的时钟,一般为72M)

6、电路原理图

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)

程序流程图及代码分析

程序流程图

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)

代码分析

① GPIO初始化部分代码

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
分析:声明一个结构体变量初始化GPIO,对系统的时钟初始化,开启GPIO时钟,配置相应的GPIO模式和IO口,具体为选择所需的IO口,将LED灯设置推挽模式输出,并设置传输速率。初始化设置好的GPIO之后,将四个LED灯的初始电平进行设置。跟LED灯对应GPIO的初始化过程相似,这里按键的GPIO的设置也按照上面的过程进行操作,这里不同的为两个按键设置成上拉输出。

② 定时器初始化部分代码

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
分析:这里声明一个结构体变量进行GPIO的初始化,开启定时器1的时钟,清除TIM1的中断待处理位(TIM1中断源),设置自动重装载寄存器周期的相关值,设置TIM1时钟频率的预分频值,设置时钟分割,TIM1向上计数模式,使能或失能TIM1外设即指定的TIM1中断,设置NVIC参数。counter作为一个全局变量用来标记开始/停止按键按下的次数,若奇数次按下,定时器使能,流水灯开始工作;若偶数次按下,定时器失能,流水灯停止工作。

③ 定时器1的回调函数的部分代码

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
分析:进入定时器1的中断之后,需要对四个LED灯相对应的状态标志位进行判断,若f1为1,则LED1被电亮,翻转LED1和LED2的状态,即将LED1熄灭,LED2点亮;若f2为1,则LED2被点亮,翻转LED2和LED3的状态,即LED2熄灭,LED3点亮,根据上述情况类推并循环往复,则可以实现所需要的流水灯效果。

④ 主函数部分代码

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)
分析:这里分别执行两个中断函数。If判断语句,当GPIO_PIN_7进入中断,即开始/停止按键被按下,改变flag标志状态位,从而实现开始/停止的功能。当GPIO_PIN_10进入中断,即设置时间的按键被按下,判断flag1标志状态位,切换至对应的延时时间,并改变flag1标志状态位,进入下一个延时时间状态,从而实现延时时间设置的功能。

设计结果分析及改进之处

设计结果

流水灯嵌入式课程设计(包含UCOSII的无仿真和无UCOSII的有仿真)

结果分析

通过两个按键来实现流水灯不同延时间隔的点亮熄灭效果的开始和停止。通过判断管脚的高低电平来判断按键是否被按下,再用状态标志位来记录此刻LED灯的状态,从而通过对状态标志位的判断切换到相应的状态并改变其状态位。这里使用两个全局变量,一个全局变量flag记录开始还是停止,一个全局变量flag1来记录延时时间是多少。同时将全局变量应用到定时器的初始化中,当为开始状态时,定时器使能,当为暂停状态时,定时器失能。对延时时间的设置,在对应的中断处理函数中,1s、2s、3s分别对应为1000、2000和3000的溢出上限值。

改进之处

① LED点亮变换
改进前:实现第一个LED灯点亮,等待相对应的时间,第二个LED灯点亮,依次循环。
改进后:通过加入状态标志位,来判断此刻LED灯所处状态,根据不同状态来执行中断回调函数。

② 延时效果实现
改进前:利用自己编写的delay函数来实现流水灯的效果,存在较多误差,难以很好精确。
改进后:使用定时器TIM1,通过中断实现效果,进行了更加准确的延时操作。

设计体会

通过此次嵌入式课程设计完成了流水灯的设计与仿真,较上学期的单片机设计,对Keil5、Proteus和STM32CubeMx软件有了更加熟练的掌握,并且对整体的编程构思到最后的具体实践过程有了更进一步的理解。
对于此次课设,还可采用UCOS-II的嵌入式操作系统来完成,即设置不同任务的优先级,后编写两个任务:流水灯任务和按键控制任务,通过已设定优先级实现两个任务之间的切换,无需进行中断的设置。按键控制可直接由if判断来实现流水灯任务的开始或停止,流水灯速度调控。
关于这点,首先我先按照正点原子的视频实现了基于UCOS-II的一个按键实验,其中对LED灯任务、蜂鸣器任务和按键任务进行了优先级的设置,涉及到一个蜂鸣器、两个LED灯和两个按键,通过按键控制蜂鸣器与LED的交互闪烁。然后从网上得到了基于UCOS-II的流水灯实现工程文件,充分理解原理过程后对其进行了实现。
虽然此次课设要求设计的流水灯功能较为简单,但在实际实现过程中,需要考虑如何使用更高效的方法、更精简的代码和更加准确的操作来实现相同的效果。这样的思想一直贯穿于我们的实际生活中的各种设计中,寻求更高效、准确和简洁的方法去实现我们的最终项目要求与目的。
在处理实际问题的过程中,思考问题的能力得到了相应提升,同时不断地编写调试代码,自己编程能力也得到了有效的强化。