工程07_01 :GPIO中断
首先需要将所有的 P1.1
修改为 P1.4
,即将(GPIO_PORT_P1,GPIO_PIN1)
修改为(GPIO_PORT_P1,GPIO_PIN4)
。
特别需要注意的是,中断处理程序中的if(status & GPIO_PIN1)
也需要修改。
然后把所有的 LED1 换成 LED2 的红灯,即将(GPIO_PORT_P1,GPIO_PIN0)
换成(GPIO_PORT_P2,GPIO_PIN0)
。
需要修改的地方有点多,不能漏。
实验的效果与上一次实验一致——绿灯闪烁 2 次,随后红灯闪烁。随着按键按下,闪烁间隔加大。直到间隔大于“喂狗”周期,看门狗复位。复位后现象循环。区别只在 LED1 换成了LED2 的红灯,以及,S1 按键换成了 S2。
工程07_02:MCLK时钟配置
只需要将 switch-case
的顺序颠倒过来。
switch(count) { case 0: tmp=CS_CLOCK_DIVIDER_128; //不分频 break; case 1: tmp=CS_CLOCK_DIVIDER_64; //2分频,以下类推 break; case 2: tmp=CS_CLOCK_DIVIDER_32; break; case 3: tmp=CS_CLOCK_DIVIDER_16; break; case 4: tmp=CS_CLOCK_DIVIDER_8; break; case 5: tmp=CS_CLOCK_DIVIDER_4; break; case 6: tmp=CS_CLOCK_DIVIDER_2; break; case 7: tmp=CS_CLOCK_DIVIDER_1; break; default: return ; }
实验效果是 LED2 的绿灯闪烁频率改为周期性的由慢变快。
一个需要说明的地方是,上电复位的时候,时钟频率还是快的,如果想要上电复位时候就是慢闪,那么在无限循环之前,就应该将始终频率设置一下。
MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_128); //如果想要上电复位时候就是慢闪,这里也要修改时钟频率
工程07_03:交通信号灯的实现
有这么几个关键的地方:
- 黄灯怎么亮
- 如何快速切换到绿灯并保持后面的执行顺序一致
首先明确怎么亮黄灯。
可以红灯和绿灯一起亮,那就是黄灯的效果。
当然也可以用 P2.3 的蓝灯代替黄灯。
或者也可以三个灯一起亮,就是白灯,也可以自己调出紫色的灯等等……
明确了这一点以后,就先可以把红绿灯切换的函数写出来。
先不考虑中断。那么就是:
switch (color){ case 0: GPIO_setOutputLowOnPin(GPIO_PORT_P2,GPIO_PIN0); //红灯灭 GPIO_setOutputHighOnPin(GPIO_PORT_P2,GPIO_PIN1); //绿灯亮 MyDelay(100); // 空循环100000 break; case 1: GPIO_setOutputHighOnPin(GPIO_PORT_P2,GPIO_PIN0); //红灯亮,2灯同时亮就是黄灯 GPIO_setOutputHighOnPin(GPIO_PORT_P2,GPIO_PIN1); //绿灯亮,2灯同时亮就是黄灯 MyDelay(15); // 空循环15000 break; case 2: GPIO_setOutputHighOnPin(GPIO_PORT_P2,GPIO_PIN0); //红灯亮 GPIO_setOutputLowOnPin(GPIO_PORT_P2,GPIO_PIN1); //绿灯灭 MyDelay(150); // 空循环150000 break; }
这段代码在作用是,根据 color
的颜色不同,决定亮哪些灯。举例来说,如果 color
当前是绿色,那么就关掉红灯、打开绿灯,然后延时绿灯的秒数。对于其他两种颜色的等也是类似的。
在执行完当前的颜色后,color
加 1,并对 3 取模,实现了0、1、2的循环。
color = (color + 1 ) % 3;
需要注意的是,样例代码给的是初始化 i=1
。为了方便操作,可选地可以让 i
改成从 0 开始。
然后就要加中断。
首先是 S1
中断,频率由慢变快。
就是实验02的内容。
与实验02类似地,将 switch-case
的顺序颠倒过来。
然后调整时钟频率。
MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, tmp); count++; count %= 8;
再添加一个中断,需要前面先声明一下。
前面已经有了一个按键的中断,只需要补上另一个按键即可。
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); //设置P1.1(s1按键)为输入模式并拉高 MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1); //清除P1.1中断 MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1); //使能GPIO1.1中断MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); //设置P1.4(s2按键)为输入模式并拉高 MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN4); //清除P1.4中断 MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4); //使能GPIO1.4中断
注意这句只要执行一次,因为他们都是一个组的。
MAP_Interrupt_enableInterrupt(INT_PORT1);
对于按键 S1
,一种简单的做法就是直接在中断处理程序令 color=0
。
这样的话,中断处理程序就是
if(status & GPIO_PIN1) //判断P1.1按键(S1键)是否按压下 { if (color != 0) color = 0; }
这是最简单的处理方式,事实上也可以被认为是正确的处理方式。
但是这样会有潜在的问题,不够优雅。
试想,假设现在处于某红灯的 Delay()
函数中,按下了按键,触发中断,此时设置 color
为绿色,然后中断返回,返回到刚才执行的地方,继续执行,于是刚才剩下的循环就会继续执行完,这显然不是预期的,并且当执行完延时以后,由于下面有 color = (color + 1 ) % 3
; 相当于又把 color
设置掉了,因此,刚才中断处理程序的 color=0
就没意义了。
一种解决方案自然是在中断中完成转换到绿灯。
例如,我们可以直接在中断处理程序中写上
GPIO_setOutputHighOnPin(GPIO_PORT_P2,GPIO_PIN1); MyDelay(100);
但是并没有根本性解决问题:中断返回以后还是不知道在哪里。
所以可不可以在中断中进行复位?那不就是回到原点了么。
不好,因为会把时钟频率也修改掉。复位以后又回到起点,意味着刚才用另一个按键修改的系统时钟频率也会被重置。
这显然也不优雅。
问题的根源其实是在于,怎么知道中断执行了,换句话说,主函数如何知道当前是正常执行的状态,还是刚刚从中断退出了。
函数的返回值。
然而,中断没有返回值。
所以可以考虑开一个全局的变量。
例如我使用 flag
作为全局变量,标识当前是中断返回的状态。
默认状态是 flag=0
,一切如常。
当进入中断的时候,设置 flag=1
。
if(status & GPIO_PIN1) //判断P1.1按键(S1键)是否按压下 { if (color != 0) flag = 1; }
中断返回。
主函数判断当前如果是由中断返回的,那么,color
重置为绿色,且清空 flag
,否则,说明程序是正常执行的,那就 color
累加并对 3 取模。
if (flag) color = flag = 0; else color = (color + 1 ) % 3; }
有了这个全局变量,上面提到的问题也解决了。
如果程序是在 Delay()
中,那么中断返回以后,我期望的效果是立刻切换到绿色灯,而不要做之前剩下的等待了。
所以很简单地,循环照常做空循环等待,但是如果 flag
是 1,就 break
出来。
//延时函数 void MyDelay(unsigned int count) { volatile uint32_t i; for(i=1000*count; i>0; i--){ if (flag) break; } return ; }
另外可能遇到一个问题,那就是出现 Memory cannot ****
错误,也就是代码写不到开发板上。
这是版本的问题。
如果 1.0 的板子,使用CMSIS
,没事。用 1.2 的板子,使用TI XDS
也没事。但是实验环境只有CMSIS
,没有TI
,如果版本是 1.2,也只能用CMSIS
,这种情况就可能会导致烧写失败,出现Memory cannot ***
错误。
这种时候,只要用自己的电脑,装了新版的 Keil 和新版的 SDK,并且固件升级到了 1.2,那么用TI XDS Debugger
就不会有问题。
但是如果一定要在机房环境调试,那么,借同学的电脑,让他用 1.2 的TI XDS Debugger
随便烧录一个程序进去,烧写一次,再回来,就又可以写的进去了。
完整代码下载:
tql
tql
太太太强了膜拜大佬
ttttql
ttttql
tql
tqqqql
t q l