时间在2021年2月3日,寒假放假在家好好学一学nRF52840
昨天喉咙就不舒服,今天就感冒了,休息一波
开发板:初雪的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(官方数据手册)
我用的野火平衡车(stm32f103)里面的硬件IIC显示的0.96OLED,移植过来的I2C/TWI
由于代码太长,所以先放实验结果:
注意,代码有错误.用我的代码会不显示,现在修改为下面这个,即可
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这章为IIC协议
NRF这边叫TWI资源, 就是两线接口,two wire interface
I2C 总线是由早期 Philips 公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息,在 nRF52 系列处理器里称为 TWI。I2C 总线可以挂载多个设备,每个设备都要唯一的地址,都可以作为一个主机或者从机,也可以成为接收器或者发送器。如下图所示:I2C 总线上可以接处理器 CPU A、处理器 CPU B、六轴 MPU6050、EEPROM 或者 ADC等。
在 nrf52840 处理器中,提供 2 条 TWI 总线 TWI0 和 TWM1,TWI 也可以称为 I2C 总线。如果TWI 作为主机带有 EasyDMA 则称为 TWIM。如果作为从机带有 EasyDMA 则称为 TWIS。
TWIM 的 TWI 主机是一个双线半双工主站,可与连接到同一总线的多个从站设备来进行通信。这里列出 TWIM 的主要功能:
• I2C 兼容
• 通信速率可以达到 100 kbps,250 kbps 或 400 kbps
• 支持时钟延长
• 带 EasyDMA
双线接口可以与具有两条线(SCL,SDA)的双向有线 AND 总线通信。该协议可以互连多达
127 个可单独寻址的设备。用于每个双线接口线的 GPIO 可以从器件上的任何 GPIO 中选择,并且可
以独立配置。这样可以极大地灵活地实现器件引脚排列,并有效利用电路板空间
低功耗:
当系统处于低功耗且不需要外围设备时,通过停止然后禁用外围设备可以实现最低功耗。可能并不总是需要 STOP 任务(外设可能已经停止),但如果发送,软件应等到收到 STOPPED 事件作为响应,然后通过 ENABLE 寄存器禁用外设
通讯过程不介绍,自己去找IIC时序讲解学去
添加驱动文件
具体在
..\..\..\..\..\..\modules\nrfx\drivers\src\nrfx_twis.c
..\..\..\..\..\..\integration\nrfx\legacy\nrf_drv_twi.c
配置SDK_CONFIG
下面说下主要的代码:
分配一个IIC实例, 使用的TWI0, TWI就是IIC
static const nrf_drv_twi_t My_IIC = NRF_DRV_TWI_INSTANCE(0); //使用IIC0
定义结构体, 结构体配置IIC的引脚 速率等
nrf_drv_twi_config_t p_config; //结构体
p_config.scl = 22;
p_config.sda = 32;
p_config.frequency = NRF_DRV_TWI_FREQ_100K ; // IIC速率
p_config.interrupt_priority = 6; //优先级
p_config.clear_bus_init = false; //初始化TWI时清除总线状态(恢复IIC为三态)
把配置写入TWI中
// IIC0 上面结构体 事件中断 无参数传递
nrf_drv_twi_init(&My_IIC, &p_config, NULL, NULL);
启动 TWI
nrf_drv_twi_enable(&My_IIC); //启动 TWI时钟
0.96OLED主要是读,没有写
于是有, 这个是写N个字节
int8_t user_i2c_write(u8 dev_id, u8 reg_addr, u8 *reg_data, u16 len)
{
ret_code_t err_code;
uint8_t write_data[MAX_WRITE_LENGTH];
if(len>MAX_WRITE_LENGTH-1)
{
err_code = 1;
return err_code;
}
write_data[0] = reg_addr;
memcpy(&write_data[1],reg_data,len);
err_code = nrf_drv_twi_tx(&My_IIC,dev_id,write_data,len+1,false);
APP_ERROR_CHECK(err_code);
return err_code;
}
然后有写一个字节的
u8 IIC_Write_1Byte(u8 SlaveAddress,u8 REG_Address,u8 REG_data)
{
ret_code_t err_code = user_i2c_write(SlaveAddress, REG_Address, ®_data, 1);
return err_code;
}
同时也可以写N个字节
u8 IIC_Write_nByte(u8 SlaveAddress, u8 REG_Address, u8 len, u8 *buf)
{
ret_code_t err_code = user_i2c_write(SlaveAddress, REG_Address, buf, len);
return err_code;
}
其中SlaveAddress 为OLED地址, 一般是0x78,但这边是0x78>>1 = 0x3c
REG_Address 一般为 0x00, 写命令
REG_Address 一般为0x40, 写数据
然后配置OLED即可
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面为具体代码
具体代码: oled.h
#ifndef __OLED_I2C_H
#define __OLED_I2C_H
#include "nrf.h"
#include "string.h"
#include "nrf_delay.h"
#define OLED_ADDRESS 0x3c //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78 >>1
#define MAX_WRITE_LENGTH 64
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
void I2C_WriteByte(uint8_t addr,uint8_t data);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
u32 mypow(u8 m,u8 n);
void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char TextSize);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
void I2C_INIT(void);
#endif
具体代码:oled.c
#include "oled.h"
#include "codetab.h"
#include "nrf_drv_twi.h"
static const nrf_drv_twi_t My_IIC = NRF_DRV_TWI_INSTANCE(0); //使用IIC0
//void My_IIC_Interrupt(nrf_drv_twi_evt_t const *p_event, void *p_context)
//{
// switch(p_event->type )
// {
// case NRF_DRV_TWI_EVT_DONE: //传输完成
// // 自己写标志
// break;
// default:
// break;
// }
//}
// 初始化 TWI,配置好引脚 开启IIC
void I2C_INIT(void)
{
nrf_drv_twi_config_t p_config; //结构体
p_config.scl = 22;
p_config.sda = 32;
p_config.frequency = NRF_DRV_TWI_FREQ_100K ; // IIC速率
p_config.interrupt_priority = 6; //优先级
p_config.clear_bus_init = false; //初始化TWI时清除总线状态(恢复IIC为三态)
// IIC0 上面结构体 事件中断 无参数传递
nrf_drv_twi_init(&My_IIC, &p_config, NULL, NULL);
// nrf_drv_twi_init(&My_IIC, &p_config, My_IIC_Interrupt,NULL);
nrf_drv_twi_enable(&My_IIC); //启动 TWI时钟
}
// 读
int8_t user_i2c_read(u8 dev_id, u8 reg_addr, u8 *reg_data, u16 len)
{
ret_code_t err_code = nrf_drv_twi_tx(&My_IIC,dev_id,®_addr,1,false);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_twi_rx(&My_IIC,dev_id,reg_data,len);
APP_ERROR_CHECK(err_code);
return err_code;
}
// 写
int8_t user_i2c_write(u8 dev_id, u8 reg_addr, u8 *reg_data, u16 len)
{
ret_code_t err_code;
uint8_t write_data[MAX_WRITE_LENGTH];
if(len>MAX_WRITE_LENGTH-1)
{
err_code = 1;
return err_code;
}
write_data[0] = reg_addr;
memcpy(&write_data[1],reg_data,len);
err_code = nrf_drv_twi_tx(&My_IIC,dev_id,write_data,len+1,false);
APP_ERROR_CHECK(err_code);
return err_code;
}
u8 IIC_Write_1Byte(u8 SlaveAddress,u8 REG_Address,u8 REG_data)
{
ret_code_t err_code = user_i2c_write(SlaveAddress, REG_Address, ®_data, 1);
return err_code;
}
u8 IIC_Read_1Byte(u8 SlaveAddress,u8 REG_Address,u8 *REG_data)
{
ret_code_t err_code = user_i2c_read(SlaveAddress, REG_Address, REG_data, 1);
return err_code;
}
u8 IIC_Write_nByte(u8 SlaveAddress, u8 REG_Address, u8 len, u8 *buf)
{
ret_code_t err_code = user_i2c_write(SlaveAddress, REG_Address, buf, len);
return err_code;
}
u8 IIC_Read_nByte(u8 SlaveAddress, u8 REG_Address, u8 len, u8 *buf)
{
ret_code_t err_code = user_i2c_read(SlaveAddress, REG_Address, buf, len);
return err_code;
}
/* 下面由STM32 硬件IIC 移植过来 */
void WriteCmd(unsigned char I2C_Command)//写命令
{
IIC_Write_1Byte(OLED_ADDRESS,0x00, I2C_Command);
}
void WriteDat(unsigned char I2C_Data)//写数据
{
IIC_Write_1Byte(OLED_ADDRESS,0x40, I2C_Data);
}
/**
* @brief OLED_Init,初始化OLED
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
nrf_delay_ms(100); //这里的延时很重要
uint8_t oled_cmd[] = "0xae, 0x20, 0x10 ,0xb0,0xc8,0x00,\
0x10,0x40,0x81,0xff,0xa1,0xa6,0xa8,0x3f,0xa4,0xd3,0x0,0xd5,\
0xf0,0xd9,0x22,0xda,0x12,0xdb, 0x20,0x8d,0x14,0xaf" ;
IIC_Write_nByte(OLED_ADDRESS,0x00,sizeof(oled_cmd),oled_cmd);
// 用上面这个 或者下面这个都行的
// WriteCmd(0xAE); //display off
// WriteCmd(0x20); //Set Memory Addressing Mode
// WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
// WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
// WriteCmd(0xc8); //Set COM Output Scan Direction
// WriteCmd(0x00); //---set low column address
// WriteCmd(0x10); //---set high column address
// WriteCmd(0x40); //--set start line address
// WriteCmd(0x81); //--set contrast control register
// WriteCmd(0xff); //亮度调节 0x00~0xff
// WriteCmd(0xa1); //--set segment re-map 0 to 127
// WriteCmd(0xa6); //--set normal display
// WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
// WriteCmd(0x3F); //
// WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
// WriteCmd(0xd3); //-set display offset
// WriteCmd(0x00); //-not offset
// WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
// WriteCmd(0xf0); //--set divide ratio
// WriteCmd(0xd9); //--set pre-charge period
// WriteCmd(0x22); //
// WriteCmd(0xda); //--set com pins hardware configuration
// WriteCmd(0x12);
// WriteCmd(0xdb); //--set vcomh
// WriteCmd(0x20); //0x20,0.77xVcc
// WriteCmd(0x8d); //--set DC-DC enable
// WriteCmd(0x14); //
// WriteCmd(0xaf); //--turn on oled panel
OLED_Fill(0x00);//全屏灭
}
/**
* @brief OLED_SetPos,设置光标
* @param x,光标x位置
* y,光标y位置
* @retval 无
*/
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd((x&0x0f)|0x01);
}
/**
* @brief OLED_Fill,填充整个屏幕
* @param fill_Data:要填充的数据
* @retval 无
*/
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
unsigned char m,n;
for(m=0;m<8;m++)
{
WriteCmd(0xb0+m); //page0-page1
WriteCmd(0x00); //low column start address
WriteCmd(0x10); //high column start address
for(n=0;n<128;n++)
{
WriteDat(fill_Data);
}
}
}
/**
* @brief OLED_CLS,清屏
* @param 无
* @retval 无
*/
void OLED_CLS(void)//清屏
{
OLED_Fill(0x00);
}
/**
* @brief OLED_ON,将OLED从休眠中唤醒
* @param 无
* @retval 无
*/
void OLED_ON(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
/**
* @brief OLED_OFF,让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
* @param 无
* @retval 无
*/
void OLED_OFF(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
/**
* @brief OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择
* @param x,y : 起始点坐标(x:0~127, y:0~7);
* ch[] :- 要显示的字符串;
* TextSize : 字符大小(1:6*8 ; 2:8*16)
* @retval 无
*/
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
unsigned char c = 0,i = 0,j = 0;
switch(TextSize)
{
case 1:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 126)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<6;i++)
WriteDat(F6x8[c][i]);
x += 6;
j++;
}
}break;
case 2:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 120)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i]);
OLED_SetPos(x,y+1);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i+8]);
x += 8;
j++;
}
}break;
}
}
//m^n函数
u32 mypow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char TextSize)
{
u8 i,temp=0;
u8 *p=&temp;
u16 number=num;
switch(TextSize)
{
case 1:
{
u8 m;
m=len;
for(i=0; i<m; i++)
{
temp=number/mypow(10,--len);
number-=temp*mypow(10,len);
temp+=48;
OLED_ShowStr(x, y, p, TextSize);
x += 6;
}
}break;
case 2:
{
u8 m;
m=len;
for(i=0; i<m; i++)
{
temp=number/mypow(10,--len);
number-=temp*mypow(10,len);
temp+=48;
OLED_ShowStr(x, y, p, TextSize);
x += 8;
}
}break;
}
}
/**
* @brief OLED_ShowCN,显示codetab.h中的汉字,16*16点阵
* @param x,y: 起始点坐标(x:0~127, y:0~7);
* N:汉字在codetab.h中的索引
* @retval 无
*/
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
unsigned char wm=0;
unsigned int adder=32*N;
OLED_SetPos(x , y);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16[adder]);
adder += 1;
}
OLED_SetPos(x,y + 1);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16[adder]);
adder += 1;
}
}
/**
* @brief OLED_DrawBMP,显示BMP位图
* @param x0,y0 :起始点坐标(x0:0~127, y0:0~7);
* x1,y1 : 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
* @retval 无
*/
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;
if(y1%8==0)
y = y1/8;
else
y = y1/8 + 1;
for(y=y0;y<y1;y++)
{
OLED_SetPos(x0,y);
for(x=x0;x<x1;x++)
{
WriteDat(BMP[j++]);
}
}
}
主函数 main.c
#include "boards.h"
#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"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_twi.h"
#include "oled.h"
extern unsigned char BMP1[];
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 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);
const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */
void My_RTCInterrupt(nrfx_rtc_int_type_t int_type);
void My_ADCInterrupt(nrf_drv_saadc_evt_t const *p_event);
#define ADC_Number 3 //有3个ADC
static nrf_saadc_value_t m_buffer_pool[ADC_Number];
static const nrf_drv_timer_t ADC_TIMER = NRF_DRV_TIMER_INSTANCE(0); //绑定定时器0
static nrf_ppi_channel_t adc_ppi_channel;
#define ADC_SCAN_TIME 500 //ADC按键扫描时间,单位ms
void MY_AdcTimer_handler(nrf_timer_event_t event_type, void * p_context);
void LED_KEY_INIT(void);
void KEY_GPIOTE_INIT(void);
void UART_INIT(void);
void TIMER4_INIT(void);
void RTC_TIMER_INIT(void);
void ADC_PPI_TIMER0_INIT(void);
int main(void)
{
LED_KEY_INIT();
KEY_GPIOTE_INIT();
UART_INIT();
TIMER4_INIT();
RTC_TIMER_INIT();
ADC_PPI_TIMER0_INIT();
I2C_INIT();
OLED_Init();
OLED_DrawBMP(0,0,128,8,BMP1);
nrf_delay_ms(500);
OLED_CLS();
nrf_delay_ms(500);
OLED_Fill(0xff);
nrf_delay_ms(500);
OLED_CLS();
nrf_delay_ms(500);
OLED_ShowStr(0, 0, (unsigned char*)"a", 1);
OLED_ShowStr(8, 1, (unsigned char*)"b", 1);
OLED_ShowStr(16, 2, (unsigned char*)"c", 1);
OLED_ShowStr(0, 3, (unsigned char*)" CSDN", 1);
OLED_ShowStr(0, 4, (unsigned char*)" jwdeng1995", 1);
OLED_ShowStr(16, 5, (unsigned char*)"hello world!", 1);
nrf_delay_ms(500);
OLED_ShowCN(0,6,0);
OLED_ShowCN(16,6,1);
OLED_ShowCN(32,6,2);
OLED_ShowCN(48,6,3);
OLED_ShowCN(64,6,4);
while(1)
{
// printf("hello world! \r\n");
}
}
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;
}
}
void My_RTCInterrupt(nrfx_rtc_int_type_t int_type)
{
static uint16_t flag500ms = 0;
if (int_type == NRF_DRV_RTC_INT_COMPARE0)
{ //无法恢复正常,只能使用1次,所以不要用比较了
// nrf_gpio_pin_toggle(LED0);
}
//滴答中断 这边是 1/ 32768 * 33 = 1ms
else if (int_type == NRF_DRV_RTC_INT_TICK)
{
if( ++flag500ms == 500 )
{
nrf_gpio_pin_toggle(LED3);
flag500ms = 0;
}
}
}
void My_ADCInterrupt(nrf_drv_saadc_evt_t const *p_event)
{
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
// 重新添加缓冲 个数为 ADC_Number个
nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, ADC_Number);
printf("%2.3fV",p_event->data.done.p_buffer[0] * 3.6 /4096);
printf("% 2.3fV",p_event->data.done.p_buffer[1] * 3.6 /4096);
printf("% 2.3fV\r\n",p_event->data.done.p_buffer[2] * 3.6 /4096);
}
}
void MY_AdcTimer_handler(nrf_timer_event_t event_type, void * p_context)
{
// 什么都做不了的
}
void LED_KEY_INIT(void)
{
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 );
}
void KEY_GPIOTE_INIT(void)
{
nrf_drv_gpiote_in_config_t key_ex_config; //按键中断配置用
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中断
}
void UART_INIT(void)
{
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);
APP_ERROR_CHECK(err_code);
}
void TIMER4_INIT(void)
{
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);
}
void RTC_TIMER_INIT(void)
{
nrf_drv_clock_init(); // 开启时钟
nrf_drv_clock_lfclk_request(NULL); // 请求低频时钟请求,没有配置事件中断
nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG; //使用SDK_CONFIG那边的默认配置
config.prescaler = 33; // 1/ (32768/33) = 1ms
nrf_drv_rtc_init(&rtc, &config, My_RTCInterrupt); // 使用RTC0,写入结构体,中断函数
nrf_drv_rtc_tick_enable(&rtc,true); //开启滴答定时器事件中断
nrf_drv_rtc_enable(&rtc); //启动RTC定时器
}
void ADC_PPI_TIMER0_INIT(void)
{
nrf_saadc_channel_config_t channel_config = //使用SDK_CONFIG那边的默认设置,通道为ADC3
NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
nrf_drv_saadc_init(NULL, My_ADCInterrupt); // 启动adc(相当于开启时钟)
nrf_saadc_channel_init(0, &channel_config); //使用通道0(0~7任用), 把默认ADC写入寄存器中
channel_config.pin_p = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN4);
nrf_saadc_channel_init(1, &channel_config);
channel_config.pin_p = (nrf_saadc_input_t)(NRF_SAADC_INPUT_AIN5);
nrf_saadc_channel_init(2, &channel_config);
nrf_drv_saadc_buffer_convert(m_buffer_pool,ADC_Number); //给缓冲BUFF加入ADC_Number个ADC值
nrf_drv_ppi_init(); //启动PPI模组
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
nrf_drv_timer_init(&ADC_TIMER, &timer_cfg, MY_AdcTimer_handler);
uint32_t ticks = nrf_drv_timer_ms_to_ticks(&ADC_TIMER, ADC_SCAN_TIME);
nrf_drv_timer_extended_compare(&ADC_TIMER,
NRF_TIMER_CC_CHANNEL0,
ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
false);
nrf_drv_timer_enable(&ADC_TIMER);
uint32_t timer_compare_event_addr = \
nrf_drv_timer_compare_event_address_get(&ADC_TIMER,NRF_TIMER_CC_CHANNEL0);
uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();
nrf_drv_ppi_channel_alloc(&adc_ppi_channel);
nrf_drv_ppi_channel_assign(adc_ppi_channel,
timer_compare_event_addr,
saadc_sample_task_addr);
nrf_drv_ppi_channel_enable(adc_ppi_channel);
}
具体代码: 代码放在下面位置, 有错误自己改, 别问我
链接:https://pan.baidu.com/s/1UlRFyJS9-Jh4xgJIyKRCxA
提取码:fai7
复制这段内容后打开百度网盘手机App,操作更方便哦