时间在2021年1月26日,寒假放假在家好好学一学
开发板:初雪的100出头那块 NRF52840 EVAL KIT
下载工具:JINLK V11(最好是JLINK V9以上 也有人用JLINK OB也行,其他的下载器STLINK,DAP不建议用)
版本号: KEIL5编程环境,CMSIS为5.3.0, NRF52840的CMSIS为8.35.0
参考资料: NRF52840-Eval-Kit-Schematic.pdf(原理图)
nRF5_SDK_17.0.2_d674dde(官方例程)
nRF5_SDK_17.0.0_offline_doc(官方文档)
nRF52840_PS_v1.1.pdf(官方数据手册)
青风NRF52832定时器章节
实现功能: 定时器计时
说明:
nRF52840有5个定时器0,1,2有4个CC寄存器, 3,4有6个CC寄存器
定时/计数器有 1)定时 2)计数 3)输入捕获Capture(有多少个CC就能捕获多少路信号) 4)输出比较(也是依赖CC) 5)任务定时触发 6)抢断清除任务,计数任务和停止任务
定时器有8 16 24 32位定时计数模式
先把头文件和skd_config的定时器内容添加/复制到工程上
OK之后开始编程了
勾选 使能定时计数器
我们现在定时时间为1ms 所以时钟频率可以选择 1MHz,
选择Timer定时器模式, 定时长度为最大16位(0~65535),优先级随便,选最低优先级
然后用定时器0
代码:
添加头文件
#include "nrf_drv_timer.h"
然后创建一个实例,来放置定时器
const nrf_drv_timer_t My_Timer0= NRF_DRV_TIMER_INSTANCE(0);
// 0~4共5个定时计数器, 随便用,记得在sdk_config那边选择好定时器就好
定义定时器结构体
nrf_drv_timer_config_t timer_cfg; //定义定时器结构体
代码:
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; //定义定时器结构体
// timer_cfg.bit_width= NRF_TIMER_BIT_WIDTH_16 ;
// timer_cfg.frequency= NRF_TIMER_FREQ_1MHz;
// timer_cfg.interrupt_priority= 7;
// timer_cfg.mode=NRF_TIMER_MODE_TIMER ;
使用默认配置(skd_config里的配置),就可以不用通过结构体赋值,然后里面有一个context(参数传递)我没有搞的
代码:
nrf_drv_timer_init(&My_Timer0, &timer_cfg,My_Timer0_Interrupt);
实例为My_Timer0, 参数配置为上面的参数, 定时器中断用自己的My_Timer0_Interrupt
下面看看定时器中断
void My_Timer0_Interrupt(nrf_timer_event_t event_type,
void * p_context)
{
}
内容暂时没有填写,等等再搞
继续写代码: 下面写的是获取1ms需要计数多少次(我计算的是1/1M *1000 =1ms 就是计数1000次就好)
uint32_t time_ticks ;
time_ticks = nrfx_timer_ms_to_ticks(&My_Timer0, 1); //算出1ms需要计数多少次
然后搞定时器匹配,让他跟我们的time_ticks(1000)比较:
nrf_drv_timer_extended_compare( // time_ticks可以直接写1000
&My_Timer0, NRF_TIMER_CC_CHANNEL0 , time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
使用定时器实例0, CC通道0(定时器0可以用0~3), 比较时间为time_ticks次(1000次), 清除比较器CC0的任务, 开启定时器0CC通道
最后启动定时器
nrf_drv_timer_enable(&My_Timer0);
下面我们来编程定时器中断函数, 500ms给LED翻转一次
void My_Timer0_Interrupt(nrf_timer_event_t event_type,
void * p_context) //1ms
{
static uint16_t flag_500ms;
switch (event_type)
{
case NRF_TIMER_EVENT_COMPARE0: // 匹配到了1ms的次数了
if( ++flag_500ms == 500 ) //500ms
{
nrf_gpio_pin_toggle(LED2);
flag_500ms = 0;
}
break;
default:
//Do nothing.
break;
}
}
最后 定时器0的通道0可以改成通道0~3其中一个 我试过了 都可以的,
NRF_TIMER_CC_CHANNEL0 改成NRF_TIMER_CC_CHANNEL2
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK改成NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK
NRF_TIMER_EVENT_COMPARE0改成NRF_TIMER_EVENT_COMPARE2
即可
也就是说4个通道都可以拿来定时的
下面我改成用定时器4,CC5来作定时器
#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
#include "nrf_uart.h"
#include "app_uart.h"
#include "nrf_drv_timer.h"
uint32_t LED0,LED1,LED2,LED3;
uint32_t KEY0,KEY1,KEY2,KEY3;
void KEY_Interrupt(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action);
#define MAX_TEST_DATA_BYTES (15U) /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
void uart_interrupt(app_uart_evt_t * p_event);
const nrf_drv_timer_t My_Timer0 = NRF_DRV_TIMER_INSTANCE(4);
// 0~4共5个定时计数器
void My_Timer0_Interrupt(nrf_timer_event_t event_type,
void * p_context);
/**
* @brief Function for application main entry.
*/
int main(void)
{
nrf_drv_gpiote_in_config_t key_ex_config; //按键中断配置用
LED0 = NRF_GPIO_PIN_MAP(0,13);
LED1 = NRF_GPIO_PIN_MAP(0,14);
LED2 = NRF_GPIO_PIN_MAP(1,9);
LED3 = NRF_GPIO_PIN_MAP(0,16);
KEY0 = NRF_GPIO_PIN_MAP(0,11);
KEY1 = NRF_GPIO_PIN_MAP(0,24);
KEY2 = NRF_GPIO_PIN_MAP(0,20);
KEY3 = NRF_GPIO_PIN_MAP(0,17);
nrf_gpio_cfg_output(LED0);
nrf_gpio_cfg_output(LED1);
nrf_gpio_cfg_output(LED2);
nrf_gpio_cfg_output(LED3);
nrf_gpio_pin_set(LED0);
nrf_gpio_pin_set(LED1);
nrf_gpio_pin_set(LED2);
nrf_gpio_pin_set(LED3);
nrf_gpio_cfg_input(KEY0,NRF_GPIO_PIN_PULLUP );
nrf_gpio_cfg_input(KEY1,NRF_GPIO_PIN_PULLUP );
nrf_gpio_cfg_input(KEY2,NRF_GPIO_PIN_PULLUP );
nrf_gpio_cfg_input(KEY3,NRF_GPIO_PIN_PULLUP );
nrf_drv_gpiote_init();//启动GPIOTE时钟,可以这么说
key_ex_config.hi_accuracy=false; // 启用低精确度PORT事件
key_ex_config.pull = NRF_GPIO_PIN_PULLUP ; //上啦
key_ex_config.sense = NRF_GPIOTE_POLARITY_HITOLO ;//下降沿
nrf_drv_gpiote_in_init(KEY0, &key_ex_config, KEY_Interrupt);
nrf_drv_gpiote_in_init(KEY1, &key_ex_config, KEY_Interrupt);
nrf_drv_gpiote_in_init(KEY2, &key_ex_config, KEY_Interrupt);
nrf_drv_gpiote_in_init(KEY3, &key_ex_config, KEY_Interrupt);
nrf_drv_gpiote_in_event_enable(KEY0, true);//启动KEY0中断
nrf_drv_gpiote_in_event_enable(KEY1, true);//启动KEY1中断
nrf_drv_gpiote_in_event_enable(KEY2, true);//启动KEY2中断
nrf_drv_gpiote_in_event_enable(KEY3, true);//启动KEY3中断
const app_uart_comm_params_t comm_params =
{
8,
6,
0,
0,
APP_UART_FLOW_CONTROL_DISABLED,
false,
NRF_UART_BAUDRATE_115200
};
uint32_t err_code;
APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_interrupt,
APP_IRQ_PRIORITY_LOWEST,
err_code);
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; //定义定时器结构体
// timer_cfg.bit_width= NRF_TIMER_BIT_WIDTH_16 ;
// timer_cfg.frequency= NRF_TIMER_FREQ_1MHz;
// timer_cfg.interrupt_priority= 7;
// timer_cfg.mode=NRF_TIMER_MODE_TIMER ;
nrf_drv_timer_init(&My_Timer0, &timer_cfg,My_Timer0_Interrupt);
uint32_t time_ticks ;
time_ticks = nrfx_timer_ms_to_ticks(&My_Timer0, 1); //算出1ms需要计数多少次
nrf_drv_timer_extended_compare( // time_ticks可以直接写1000
&My_Timer0, NRF_TIMER_CC_CHANNEL5 , time_ticks, NRF_TIMER_SHORT_COMPARE5_CLEAR_MASK, true);
/* 使用定时器实例0, CC通道0(定时器0可以用0~3), 比较时间为time_ticks次(1000次),
清除比较器CC0的任务, 开启定时器0CC通道 */
nrf_drv_timer_enable(&My_Timer0);
// uint8_t str[]="hello world!\r\n";
// uint8_t i=0,str1[20];
while(1)
{
// printf("hello world! \r\n");
// while(str[i]!='\0')
// {
// app_uart_put(str[i]);
// i++;
// }
// nrf_delay_ms(1000);
// i=0;
// if( NRF_SUCCESS == app_uart_get(str1))
// printf("%s\r\n",str1);
}
}
void KEY_Interrupt(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
if(KEY0 == pin)
nrf_gpio_pin_toggle(LED0);
if(KEY1 == pin)
nrf_gpio_pin_toggle(LED1);
if(KEY2 == pin)
nrf_gpio_pin_toggle(LED2);
if(KEY3 == pin)
nrf_gpio_pin_toggle(LED3);
}
void uart_interrupt(app_uart_evt_t * p_event)
{
uint8_t dat;
if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_communication);
}
else if (p_event->evt_type == APP_UART_FIFO_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_code);
}
else if (p_event->evt_type == APP_UART_DATA_READY)
{//数据已到达串口 , 可以读数据了
app_uart_get(&dat); //读取数据
app_uart_put(dat); // 原路发回
}
else if (p_event->evt_type == APP_UART_TX_EMPTY)
{//发送完成
//发送完成不知道要做什么的,可以点个灯提醒
nrf_gpio_pin_toggle(LED0);
}
}
void My_Timer0_Interrupt(nrf_timer_event_t event_type,
void * p_context) //1ms
{
static uint16_t flag_500ms;
switch (event_type)
{
case NRF_TIMER_EVENT_COMPARE5: // 匹配到了1ms的次数了
if( ++flag_500ms == 500 ) //500ms
{
nrf_gpio_pin_toggle(LED1);
flag_500ms = 0;
}
break;
default:
//Do nothing.
break;
}
}
链接:https://pan.baidu.com/s/1r9P4K9xvaur8jjbYPQ-T0Q
提取码:krx5
复制这段内容后打开百度网盘手机App,操作更方便哦
文件解压在这里, 有什么问题自己解决 别问我