最近使用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不灵的,可以参考修改一下