作业|学习

GPIO中断与系统时钟树配置

凝神长老 · 11月19日 · 2018年 · · · · · · · · 2079次已读

本文写于 2018年11月19日,距今已超过 1 年,距 2020年03月27日 的最后一次修改也已超过 3 个月,部分内容可能已经过时,您可以按需阅读。如果图片无法显示或者下载链接失效,请给我反馈,谢谢!


5 4 投票
评分

工程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随便烧录一个程序进去,烧写一次,再回来,就又可以写的进去了。

完整代码下载:

5 4 投票
评分
5 4 投票
评分
订阅评论动态
提醒
guest
24 评论
最新
最旧 得票最多
行内反馈
查看所有评论
22222
22222 Chrome 86.0.4240.111 Windows 10
2020年11月24日 18:24
我对这篇文章的评分 :
     

ttttql

asdas
asdas Chrome 86.0.4240.198 Windows 10
2020年11月24日 10:59
我对这篇文章的评分 :
     

tql

Qweasdzxc
Qweasdzxc Safari 605.1.15 Mac OS X 10_15_6
2020年11月17日 09:57
我对这篇文章的评分 :
     

tqqqql

qweasdzxc
qweasdzxc Safari 605.1.15 Mac OS X 10_15_4
2020年11月5日 15:38
我对这篇文章的评分 :
     

t q l

tql
tql Edge 85.0.564.51 Windows 10
2020年9月17日 17:35

1111

AAA
AAA Chrome 80.0.3987.122 Windows 10
2020年3月3日 18:44

tttttql

dd
dd Opera 12.14 Windows Vista
2019年12月23日 22:02

666

xxx
xxx Chrome 76.0.3809.100 Windows 10
2019年12月22日 21:37

dalao

enheng
enheng Firefox 70.0 Windows 10
2019年11月24日 22:26

1

mion
mion Edge 18.18362 Windows 10
2019年11月24日 21:24

tql

ma
ma QQ 8.1.8.4260 Android 9 | HUAWEI RVL-AL09
2019年11月24日 21:17

tql

zzjs
zzjs Edge 18.18362 Windows 10
2019年11月23日 18:12

tql

beautifulsoup
beautifulsoup Chrome 78.0.3904.108 Windows 10
2019年11月23日 15:28

tql

ILoveChina
ILoveChina Chrome 78.0.3904.108 Windows 10
2019年11月23日 13:16

nbnb

1
1 Chrome 79.0.3941.4 Windows 10
2019年11月22日 17:29

tql

billbiscuit
billbiscuit Edge 18.18362 Windows 10
2019年11月22日 17:21

666

hahaha
hahaha Chrome 78.0.3904.97 Windows 10
2019年11月18日 23:17

666

1
1 Chrome 78.0.3904.70 Windows 10
2019年11月13日 10:21

666

aix
aix Chrome 78.0.3904.97 Windows 10
2019年11月10日 09:59

tttql

Demonnue
Demonnue Chrome 68.0.3440.106 Windows 10
2019年10月2日 19:42

zzwtql
zzwtql Firefox 68.0 Windows 10
2019年8月18日 13:52

您也太强

L
L Chrome 69.0.3497.92 Windows 10
2018年12月28日 21:07

感谢!

lala
lala Chrome 70.0.3538.102 Mac OS X 10_14_0
2018年11月27日 18:34

好人zzw

caiji
caiji Chrome 70.0.3538.102 Windows 10
2018年11月24日 11:39

tql