nrf51822学习之PPI裸板程序之对于定时器0计数方式的疑惑

来源:互联网 发布:淘宝详情页的制作 编辑:程序博客网 时间:2024/05/17 06:01

总体功能:

有两种方式来使能或者关掉PPI频道:通过定时器2比较事件来触发定时器0开始计数。通过
定时器1比较事件来触发定时器0停止计数。整个过程不需要CPU 参与,和中断触发类型有点相
似。

定时器初始化:

定时器0的设置比较简单了设置为普通的计数模式,依次计数。BITMODE设置为
24bit.定时器1和定时器2的设置类似,区别就是为了错开比较事件的时间,也就是通PPI设置的定时器0的打开计数和关闭时间,因此CC 寄存器的预设值有区别:

void timer0_init(void)
{
      NRF_TIMER0->MODE = TIMER_MODE_MODE_Counter; //设置定时器位计数模式.
      NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_24Bit; // 24-bit模式.
}

定时器2CC寄存器预设值设为了0x7FFF,通过之前所讲的定时器设置,这个比较触发的时间大概是1s,定时器1CC寄存器预设值设为了0xFFFF,这个比较触发的时间大概是2s,因此定时器0的开始任务与结束任务时间大概是1S,因为定时器1和2对本文没有多大帮助,故这里不列出。

下来看看ppi的配置:

void ppi_init(void)
{
     // 通道 0 的 EFP 和 TEP 设置
     //把定时器 1 的比较事件作为事件,定时器 0 的停止作为任务
     //通过定时器 1 比较事件来触发定时器 0 停止
     NRF_PPI->CH[0].EEP = (uint32_t)(&NRF_TIMER1->EVENTS_COMPARE[0]);
     NRF_PPI->CH[0].TEP = (uint32_t)(&NRF_TIMER0->TASKS_STOP);

     // 通道 1 的 EFP 和 TEP 设置
     //把定时器 2 的比较事件作为事件,定时器 0 的开始作为任务
     //通过定时器 2 比较事件来触发定时器 0 开始
     NRF_PPI->CH[1].EEP = (uint32_t)(&NRF_TIMER2->EVENTS_COMPARE[0]);
     NRF_PPI->CH[1].TEP = (uint32_t)(&NRF_TIMER0->TASKS_START);

     // 使能 PPI 通道 1 和通道 0
     NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos) |
            (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);
}
PPI实际上提供了一种直连的机制,这种机制可以把一个外设发生的事件(event)来触发另一个外设的任务(task) ,整个过程不需要 CPU 进行参与。因此一个任务(task)通过PPI通道和事件(event)进行互连。PPI通道由两个终点寄存器组成,分别为:

事件终点寄存器(EEP)和任务终点寄存器(TEP)
可以把外设任务(task)通过任务寄存器的地址与任务终点寄存器(TEP)进行赋值。同理,也可以把外设事件通过事件(event)寄存器的地址与事件终点寄存器(EEP)进行赋值 。


我的疑惑如下:

定时器初始化为技术模式,那么触发技术的应该是count任务,在手册里也是这样说明的:

In counter mode, the TIMER's internal Counter register is incremented by one each time the COUNT task is triggered, that is, the timer frequency and the prescaler are not utilized in counter mode. Similarly, the COUNT task has no effect in Timer mode.

也就是应该触发COUNT task任务,而本例程里触发的确实start和stop任务,为什么呢?

本例程是这样设置ppi的:

NRF_PPI->CH[0].TEP = (uint32_t)(&NRF_TIMER0->TASKS_STOP);
NRF_PPI->CH[1].TEP = (uint32_t)(&NRF_TIMER0->TASKS_START);

而且本例程实验还成功了,我更加的疑惑!!!!????



这里上传青风写的例程说明文档:

http://download.csdn.net/detail/chengdong1314/9527113

例程:实验9:ppi的使用  

http://download.csdn.net/detail/chengdong1314/9527773


经过和淘宝客服讨论,我发现了一个我犯了一个致命的错误,原例程中的PPI的功能只是打开TIM0,而不是增加TIM0的计数器,我一直误解为PPI是增加计数器,而忽略了主函数while循环中的至关重要的一句话:NRF_TIMER0->TASKS_COUNT         = 1;

原例程的while循环如下:

机制是这样的:

定时器1比较事件 ->PPI ->打开计数器0

主循环NRF_TIMER0->TASKS_COUNT         = 1;       -》计数器0加1

定时器2比较事件 ->PPI ->关闭计数器0


为了验证我的想法,我这样改主函数,把while循环里的延时关掉,将可以看到,我们的等将是一直闪烁的,起码不是本来的现象,修改后的主函数如下:

下载程序后可以看所有的灯都是亮的,最少有两个灯同时在亮,说明在一次TIM1比较事件和TIM2比较事件之间,原来的程序做到了while循环只是循环了一次。

这时候我就很纳闷,TIM1比较事件和TIM2比较事件之间的时间是1s,应该计数器会增加10次才对,所以可以猜测这里的波形一定是不规则的,LED管脚不行如下:

波形确实是不规则的。

如果去掉延时那么波形就应该是规则的,波形如下:

波形是规则的,这幅图从宏观上来看应该是有变换的,其中部分是while循环的周期,短周期形成的长周期就是TIM1比较事件和TIM2比较事件之间的时间,没有短周期的就是TIM1未溢出的时间,如下:

实验视频现象如下:http://download.csdn.net/detail/chengdong1314/9567341


感谢sinat_35399891的评论,让我意识到依旧还有问题,找了好久,终于找到了问题,现在对本实验做如下补充:
总体来看NRF_TIMER0->TASKS_COUNT = 1;这句话的时候COUNT值会+1的只是在T2比较事件到T1比较事件内,也就是1s到2s这段时间,但是这时候的变化就是以100ms为间隔的,在0s到1s的时间里,COUNT值是不会改变的。
但是从波形来看变化规律并不是100ms,而是400ms左右,为什么呢?

我们可以再回来看看电路原理图:

也就是说LED并不是从P0.16开始的,而是从P0.18开始,这点十分值得注意,再看看给管脚赋值的程序:

nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT2, (uint8_t)NRF_TIMER0->CC[0]);

而其中的NRF_GPIO_PORT_SELECT_PORT2从如下看到内容:

/**
 * @enum nrf_gpio_port_select_t
 * @brief Enumerator used for selecting between port 0 - 3.
 */
typedef enum
{
    NRF_GPIO_PORT_SELECT_PORT0 = 0,           ///<  Port 0 (GPIO pin 0-7)
    NRF_GPIO_PORT_SELECT_PORT1,               ///<  Port 1 (GPIO pin 8-15)
    NRF_GPIO_PORT_SELECT_PORT2,               ///<  Port 2 (GPIO pin 16-23)
    NRF_GPIO_PORT_SELECT_PORT3,               ///<  Port 3 (GPIO pin 24-31)
} nrf_gpio_port_select_t;

也就是说捕获得到的值是传给了NRF_GPIO_PORT_SELECT_PORT2,那么P0.16就是每100ms加一次,而LED0的位置是P0.18,那么他就应该是没400ms加一次,因为他是在滴2位上,计数器寄到第2位进位要计4次

这样,我们的实验结果就很清楚了,下面这就是本实验的波形:

确实变化单位是400ms,但是波形并不是有规律的,从低电平来看,有低电平维持400ms的,也有1s的甚至还有1.4s的,实验结果也证明了点灯时间是有长有短的,因为博客不能上传视频,所以视频我上传到我的资源你呢,请看:http://download.csdn.net/detail/chengdong1314/9567338

1 0
原创粉丝点击