NRF52840学习历程(八)IIC协议0.96OLED屏幕

时间在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, &REG_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,&reg_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, &REG_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,操作更方便哦

猜你喜欢

转载自blog.csdn.net/jwdeng1995/article/details/113618362