nrf51822硬件IIC实现有点蛋疼,详细软件IIC实现方法



最近使用51822的IIC,由于这款芯片自带硬件IIC,遂优先考虑硬件IIC方案

但其实项目进行的过程中十分不顺利


主要过程如下


先在SDK10.0中找这个文件twi_hw_master.c这个文件

其还有twi_master_config.h这个头文件

用win10文件夹里面搜索即可


其实里面的内容很简单


twi_master_config.h

#ifndef TWI_MASTER_CONFIG
#define TWI_MASTER_CONFIG


#define TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER 18 //定义了IIC总线的管脚
#define TWI_MASTER_CONFIG_DATA_PIN_NUMBER 19


#endif


其实就是定义了scl和sda的管脚




另一个c文件有有点料了

其实就是以下两个函数


//IIC主设备写入函数
bool twi_master_write(uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
    uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for EVENTS_TXDSENT event*/
                                            //这里就是定义了超时

    if (data_length == 0)                    //长度为0直接返回
    {
        /* Return false for requesting data of size 0 */
        return false;
    }


    NRF_TWI1->TXD           = *data++;												//先载入数据    
    NRF_TWI1->TASKS_STARTTX = 1;															//开始发送数据


    /** @snippet [TWI HW master write] */
    while (true)
    {
        while (NRF_TWI1->EVENTS_TXDSENT == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
        {
            // Do nothing.等待数据发送完成
        }


        if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)			//如果数据发送失败,进行错误处理
        {
            // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
            // Product Anomaly Notification document found at 
            // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
            NRF_TWI1->EVENTS_ERROR = 0;												//重置错误标志
            NRF_TWI1->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; //失能总线
            NRF_TWI1->POWER        = 0;												//关闭总线电源
            nrf_delay_us(5);
            NRF_TWI1->POWER        = 1;												//开启总线电源
            NRF_TWI1->ENABLE       = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;	//使能总线


            (void)twi_master_init();													//总线初始化


            return false;																			//返回失败标志
        }
        NRF_TWI1->EVENTS_TXDSENT = 0;													//数据发送成功后,清楚已发送标志
        if (--data_length == 0)																//如果数据发送完了,就直接跳出
        {
            break;
        }


        NRF_TWI1->TXD = *data++;															//载入下一位数据并发送
    }
    /** @snippet [TWI HW master write] */


    if (issue_stop_condition)																	//等待应答
    {
        NRF_TWI1->EVENTS_STOPPED = 0;													//先不停止总线
        NRF_TWI1->TASKS_STOP     = 1;													//停止传输
        /* Wait until stop sequence is sent */ 
        while(NRF_TWI1->EVENTS_STOPPED == 0) 									//等待总线停止
        {
            // Do nothing.
        }
    }
    return true;
}




/** @brief Function for read by twi_master. 
 */




//IIC主设备读取函数
bool twi_master_read(uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
    uint32_t timeout = MAX_TIMEOUT_LOOPS; 				/* max loops to wait for RXDREADY event*/


    if (data_length == 0)
    {
        /* Return false for requesting data of size 0 */
        return false;
    }
    else if (data_length == 1)																				//如果只有一位数据,传输完停止总线
    {
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
    }
    else
    {
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND;			//多于一位传输完挂起总线
    }


    NRF_PPI->CHENSET          = PPI_CHENSET_CH0_Msk;
    NRF_TWI1->EVENTS_RXDREADY = 0;																		//先清除接收完成标志
    NRF_TWI1->TASKS_STARTRX   = 1;																		//开始接收


    /** @snippet [TWI HW master read] */
    while (true)
    {
        while (NRF_TWI1->EVENTS_RXDREADY == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
        {
            // Do nothing.等待接收
        }
        NRF_TWI1->EVENTS_RXDREADY = 0;													//不论有没有接收成功,先清楚接收完成标志


        if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)				//超时后,并且传错误标志位置位,进行处理
        {
            // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
            // Product Anomaly Notification document found at
            // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
            NRF_TWI1->EVENTS_ERROR = 0;									//先清楚错误标志
            NRF_TWI1->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;				//以下是重启总线
            NRF_TWI1->POWER        = 0;
            nrf_delay_us(5);
            NRF_TWI1->POWER        = 1;
            NRF_TWI1->ENABLE       = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;


            (void)twi_master_init();


            return false;								//返回失败标志
        }


        *data++ = NRF_TWI1->RXD;																//把数据读到输出型参数里面


        /* Configure PPI to stop TWI master before we get last BB event */
        if (--data_length == 1)																	//在临近剩下一位数据时,传输完停止总线
        {
            NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
        }


        if (data_length == 0)																		//如果传完就退出
        {
            break;
        }


        // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
        // Product Anomaly Notification document found at
        // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
        nrf_delay_us(20);
        NRF_TWI1->TASKS_RESUME = 1;														//总线恢复传输
    }
    /** @snippet [TWI HW master read] */


    /* Wait until stop sequence is sent */										//等待总线停止
    while(NRF_TWI1->EVENTS_STOPPED == 0)
    {
        // Do nothing.
    }
    NRF_TWI1->EVENTS_STOPPED = 0;															//清楚总线停止标志


    NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk;
    return true;
}

其实主要的就是这两个函数,但实际使用中很蛋疼,总是读不出来

遂自己用51单片机的程序改了下

#define SLC_PIN					18				
#define SDA_PIN					19



#define delay() 		nrf_delay_us(5)																//IIC总线延时单位

#define SCL_1()			nrf_gpio_pin_set(SLC_PIN)					
#define SCL_0()			nrf_gpio_pin_clear(SLC_PIN)

#define SDA_1()			nrf_gpio_pin_set(SDA_PIN)		
#define SDA_0()			nrf_gpio_pin_clear(SDA_PIN)



																//使用这个函数设置为上拉输出,但其实是可以读管脚状态的
void set_pullup_output(uint8_t pin_no)
{
		
	NRF_GPIO->PIN_CNF[pin_no] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
																| (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)							//驱动能力设置为标准模式
																| (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)							//设置上拉
																| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)					//输入路径设置为连接后可读管脚状态		
																| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);							//设置为输出	
	
}


bool read_pin(uint8_t pin_no)											//读取pin状态
{
		return  ((NRF_GPIO->IN >> pin_no) & 1UL); 
}


void at24c02_init(void)
{
	set_pullup_output(18);					//18,19管脚设置为上拉输出
	set_pullup_output(19);
	
	SDA_1();
	delay();
	SCL_1();
	delay();
	
}


void start()  //开始信号
{	
	SDA_1();
	delay();
	SCL_1();
	delay();
	SDA_0();
	delay();
}

void stop()   
{
	SDA_0();
	delay();
	SCL_1();
	delay();
	SDA_1();
	delay();
}


void respons()  
{
	uint32_t i = 0;
	
	SCL_1();
	delay();
	while((read_pin(SDA_PIN))&&(i<(16*250)))
		i++;
	
	SCL_0();
	delay();
}


void write_byte(uint8_t date)
{
	uint8_t i,temp;
	bool bit;
	temp=date;
	
	for(i=0;i<8;i++)
	{
		bit = (temp&0x80);					//取最高位
		temp=temp<<1;
		SCL_0();
	  delay();
		nrf_gpio_pin_write(SDA_PIN, bit);
		delay();
		SCL_1();
		delay();
	}
	SCL_0();
	delay();
	SDA_1();
	delay();
}

uint8_t read_byte()
{
	uint8_t i,k;
	
	SCL_0();
	delay();
	SDA_1();
	delay();
	for(i=0;i<8;i++)
	{
		SCL_1();
		delay();	
		k=(k<<1)|read_pin(SDA_PIN);
		SCL_0();
		delay();	
	}
	return k;
}


void write_add(uint8_t address,uint8_t date)
{
	start();
	write_byte(0xa0);
	respons();
	write_byte(address);
	respons();
	write_byte(date);
	respons();
	stop();
}


uint8_t read_add(uint8_t address)
{
	uint8_t date;
	start();
	write_byte(0xa0);
	respons();
	write_byte(address);
	respons();
	start();
	write_byte(0xa1);
	respons();
	date=read_byte();
	stop();
	return date;
}

改了下,用来读写AT24CXX效果杠杠的

如果有使用硬件IIC不灵的,可以参考修改一下


														           

   










你可能感兴趣的:(嵌入式软件)