定义一个标志位 bit flag=0;
主各序结构:
while(1)
{
if(flag==0)
{.......
.程序1
}
if(flag==1)
{.......
程序2
}
}
按键检测可用中断,中断程序中改变flag的值
stm32输入配置有上拉,下拉,浮空三种模式,这三种模式的功能是不一样的。
功能区别如下:
1、上拉输入:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!强弱只是上拉电阻的阻值不同,没有什么严格区分。
2、下拉输入:就是把电压拉低,拉到GND。与上拉原理相似。
3、浮空输入:浮空(floating)就是逻辑器件的输入引脚即不接高电平,也不接低电平。由于逻辑器件的内部结构,当它输入引脚悬空时,相当于该引脚接了高电平。一般实际运用时,引脚不建议悬空,易受干扰。通俗讲就是让管脚什么都不接,浮空着。
扩展资料
STM32三种输出方式的不同:
1、推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
2、开漏输出:输出端相当于三极管的集电极。要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。
3、复用输出:可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。端口必须配制成复用功能输出模式(推挽或开漏)。
stm32cude界面切换白色背景的方法:
1、点击工具选项。
2、点击显示二字。
3、点击颜色图标。在弹出的图形窗口颜色中的颜色下拉按钮选择白色即可。根据查询相关信息可知,stm32cude是一款绘图软件,广泛应用于平面设计、建筑等领域,因其功能众多深受相关专业人士的喜爱。
这一章比上一章内容多了不少。第一章完成了任务切换功能,这一章在任务切换功能上增加了以下几个功能。
1.改变特权级,加入SVC异常
2.增加优先级,使得内核可以抢占。
3.增加了滴答定时器中断功能,使得同优先级的任务以时间片方式调度。
4.增加延时函数。
接下来一项一项介绍。
1. 改变特权级
第一章中,所有的程序都是运行在特权级下。在中断中时切换到内核模式,在任务中切换到线程模式(Thread),但是权限都是特权级,意味着程序对内存中所有的数据都有修改的权限。此处加入两张图,通过修改寄存器,可以在退出中断后,在任务中运行即线程模式时权限是非特权级,这样在线程模式时就不能够更改内核模式下的数据了,程序的更具有健壮性。
更改特权级只能在特权级下更改,所以通过在PendSV最后加入红色字体部分来更改了特权级。
__ASM void PendSVPopData()
{
extern PendSVFirst;
extern currTCB;
extern nextTCB;
PRESERVE8
LDR R0,=currTCB //R0=currTCB
LDR R1,=nextTCB //R1=nextTCB
LDR R1,[R1] //R1=*R1
STR R1,[R0] //*R0=R1 currTCB=nextTCB完成了指向新的任务TCB的工作
LDR R0,[R1] //R0=*R1 R0保存了TCB堆栈栈顶的指针
LDMIA R0!,{R4-R11} //依次弹出R4-R11,完成后R0=R0+0x20
MSR PSP,R0 //PSP=R0
ORR LR,LR,#0x04 //LR=LR|0x04,表示函数返回后使用PSP指针
//使程序运行在非特权级,设置CONTROL[0]位为1,这样内核级和用户级就分开了,即是某个线程出现了问题也不会影响内核
LDR R1,=0x3
MSR CONTROL,R1
ISB
CPSIE I
BX LR
nop
}
同时要注意在非特权级(用户级)下只有触发异常才可以进入重新进入特权级,因此额外加入了SVC异常来主动触发中断。
还记得我们上一章讲过的发起任务调度的两种方式吗?
1.产生异常。
2.systick定时器中断。
其中第一条就是SVC异常中断。SVC异常用于产生系统调用,它的优先级最高,一经调用立刻进入此异常,因此,通过调用SVC异常,OS就进入了内核态(handler模式),在此就可以进行任务切换了。这种方式发起任务调度就不必等到systick定时器中断产生再发生任务调度了。
在任务中调用SvcTaskSwitch()就可以进行一次任务切换,这是自己定义的函数。SVC具体细节可以在网上查看相关资料。
2. 增加优先级功能
优先级功能参考了FreeRTOS的设计,通过列表和列表项的方式实现。
简单来讲,为了实现这个功能,我们设置了不同的列表,如果我们设置优先级共有8个,则新建8个优先级列表priorityReadyList[8]存储处于就绪态的任务,新建一个delayedList,存储处于延时的任务,新建一个pendList,存储处于挂起态的任务。所有的任务必然存在于这三种列表中。
列表又由列表项组成,列表中的列表项以双向链表的形式组合在一起,每一个列表项又存储了一个任务的TCB,这样就可以找到相应的任务。
在任务切换时,首先找到一个目前优先级最高的任务,OSFindMaxPriorityTask()。如果找到的这个任务跟当前任务的优先级相同,那么就指向当前任务在列表中的下一个任务,来做切换,如果找到的任务优先级更高,那么直接切换高优先级的任务
3. 滴答定时器
滴答定时器的中断时间时1ms,也是时间片的时间。同优先级的任务每个运行1ms再切换。
systemTicks是任务运行的时间,系统初始化时赋值为0。在此我们不考虑溢出的问题,因为systemTicks是一个uint32_t的值,在此最大值代表约50天,因此在这个简易系统中不考虑溢出的情况。
其中需要注意的一点是判断任务的延时是否到达。其实很简单,如果有一个任务的延时时间到了,在延时列表中删除这个任务,在就绪列表中增加这个任务。我们怎么在延时列表中找到这个任务呢?因为列表中的列表项是按照readyTime升序排列的,因此通过我们前面在列表中特意设的最后列表的最后一项可以轻易的根据previous找到列表中的第一项。更新完任务后不要忘了更新下一项延时任务将要到达的时间。
在初始话列表的过程中我们给列表最后一项赋予了一个很大的值0x3ffffffff,因此可以任务永远不会到达这个时间。在列表中添加的项都会在它的前面。
4. 增加延时函数。
在第一章,我们时通过无意义的while(i--)来达到延时的目的,但这是阻塞运算,程序会卡在这个地方,满足不了实际的需要。OS中的延时函数会发生任务的调度,这样才不会浪费资源。
OSDelay的主要功能就是把当前任务挂起,在就绪列表中删除当前的任务,把任务加入到延时的列表中,更新其将要延时的时间,然后寻找下一个优先级最高的任务,进行切换。
最后设计了几个小实验,来验证程序是否正确运行。
设计了几个实验
1.两个小灯优先级相同,验证同优先级下的时间片调度。ok
void Task1()
{
int j = 0;
while(1)
{
j=20000000;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
while(j!=0)
j--;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
j=20000000;
while(j!=0)
j--;
}
}
void Task2()
{
int i = 0;
while(1)
{
i=10000000;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
while(i!=0)
i--;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
i=10000000;
while(i!=0)
i--;
}
}
2.两个任务优先级相同,验证延时功能是否有效 ok
void Task1()
{
while(1)
{
OSDelay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
OSDelay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
}
}
void Task2()
{
while(1)
{
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
}
}
3.验证优先级不同,任务一优先级高,任务二优先级低,任务一一直运行,小灯暗灭切换,可以看到任务二不运行,小灯一直亮
void Task1()
{
int i = 0;
while(1)
{
i = 20000000;
while(i!=0)
i--;
//OSDelay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
i = 20000000;
while(i!=0)
i--;
//OSDelay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
}
}
void Task2()
{
while(1)
{
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
}
}
4.任务一优先级高,任务二优先级低,任务一程序中有挂起3秒。可以看到在挂起的这段时间内任务二会切换,一但不挂起,任务二灯不会切换
void Task1()
{
int i = 0;
while(1)
{
i = 100000000;
while(i!=0)
i--;
//OSDelay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
i = 100000000;
while(i!=0)
i--;
OSDelay(5000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
}
}
void Task2()
{
while(1)
{
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
OSDelay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
}
}
程序链接如下,实验用的是STM32F407的开发板
链接:
提取码:j5hw
stm32超轻量操作系统之任务调度
stm32超轻量操作系统之信号量与互斥量
调整显示素材资源坐标。stm32横屏竖屏切换需要调整显示素材资源坐标。基于stm32+emwin系统上开发lcd设备图形界面时,屏幕横屏变竖屏切换的功能需要调整显示素材资源坐标,更新屏幕页面缓存,最终刷新页面。
stm32按下按键换到下一页如下。STM32CubeIDE快捷键很多,可以通过 Help Show Active Keybindings… 查看当前可用快捷键;也可以在 Window Preferences General Keys 中查看修改快捷键。
本文标签:stm32功能切换