完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
同样的程序,我今天上午可以实现读取的数据是正确的,然后我把读取给注释掉了,再次写入,然后断电,注释掉写入程序,恢复了读取,结果oled屏就完全不显示东西了。后来我把程序恢复原样,也没有反应了。我想问一下是我上述操作有问题吗,或者猜测一下可能是哪里出现了问题呢
单步执行了几次,它有时会卡在启动传输后的i2c_Wait,有时卡在写地址后面的这个i2c_Wait 我的单片机用的是k60,eeprom用的是24c02 不知道哪里错了,新手小白,求大佬指教 以下是我的程序: 谢谢~ #include "common.h" #include "include.h" #include "port.h" #include "i2c.h" #define AT24C02_i2c_ADDRESS 0x50 unsigned char MasterTransmission; unsigned char SlaveID; I2C_MemMapPtr I2CN[2] = {I2C0_BASE_PTR, I2C1_BASE_PTR}; //定义两个指针数组保存 I2CN 的地址 /* * 把I2C通信的每个小步骤都用宏定义来实现,方便编写顶层函数 * 此宏定义参考飞思卡尔公司例程修改所得 */ #define i2c_DisableAck(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TXAK_MASK // #define i2c_RepeatedStart(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_RSTA_MASK //启动信号 #define i2c_Start(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TX_MASK; I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_MST_MASK //暂停信号 #define i2c_Stop(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_MST_MASK; I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TX_MASK //进入接收模式(应答) #define i2c_EnterRxMode(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TX_MASK; I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TXAK_MASK //进入接收模式(不应答) #define i2c_PutinRxMode(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TX_MASK //等待 I2C0_S #define i2c_Wait(I2Cn) while(( I2C_S_REG(I2CN[I2Cn]) & I2C_S_IICIF_MASK)==0) {} I2C_S_REG(I2CN[I2Cn]) |= I2C_S_IICIF_MASK; //写一个字节 #define i2c_write_byte(I2Cn,data) I2C_D_REG(I2CN[I2Cn]) = data /*! * @Brief I2C初始化,设置波特率 * @param I2Cn_e I2C模块(I2C0、I2C1) * @param baud 期待的波特率 * @Return 实际的波特率 * @since v5.0 * Sample usage: i2c_init(I2C0,400*1000); // 初始化I2C0,期待的波特率为400k */ uint32 i2c_init(I2Cn_e i2cn, uint32 baud) { if(i2cn == I2C0) { /* 开启时钟 */ #if defined(MK60DZ10) SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK; //开启 I2C0时钟 #elif defined( MK60F15) SIM_SCGC4 |= SIM_SCGC4_IIC0_MASK; //开启 I2C0时钟 #endif /* 配置 I2C0功能的 GPIO 接口 */ if((I2C0_SCL_PIN == PTB0) || (I2C0_SCL_PIN == PTB2) || (I2C0_SCL_PIN == PTD8) ) { PORT_FuncInit (I2C0_SCL_PIN, ALT2 | ODO | PULLUP ); } else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? if((I2C0_SDA_PIN == PTB1) || (I2C0_SDA_PIN == PTB3) || (I2C0_SDA_PIN == PTD9) ) PORT_FuncInit (I2C0_SDA_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? } else { /* 开启时钟 */ #if defined(MK60DZ10) SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK; //开启 I2C1时钟 #elif defined(MK60F15) SIM_SCGC4 |= SIM_SCGC4_IIC1_MASK; //开启 I2C1时钟 #endif /* 配置 I2C1功能的 GPIO 接口 */ if(I2C1_SCL_PIN == PTE1) PORT_FuncInit (I2C1_SCL_PIN, ALT6 | ODO | PULLUP ); else if(I2C1_SCL_PIN == PTC10) PORT_FuncInit (I2C1_SCL_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? if(I2C1_SDA_PIN == PTE0) PORT_FuncInit (I2C1_SDA_PIN, ALT6 | ODO | PULLUP ); else if (I2C1_SDA_PIN == PTC11) PORT_FuncInit (I2C1_SDA_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? } /* 设置频率 */ // I2C baud rate = bus speed (Hz)/(mul × SCL divider) 即这里 50MHz/(1 ×128)=390.625kHz // SDA hold time = bus period (s) × mul × SDA hold value // SCL start hold time = bus period (s) × mul × SCL start hold value // SCL stop hold time = bus period (s) × mul × SCL stop hold value //查表 ICR 对应的 SCL_divider ,见 《K60P144M100SF2RM.pdf》第1468页的 I2C Divider and Hold Values uint16 ICR_2_SCL_divider[0x40] = { 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68, 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240, 160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960, 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840 }; uint8 mult; if(bus_clk_khz <= 50000)mult = 0; //bus 一分频 else if(bus_clk_khz <= 100000)mult = 1; //bus 二分频 else mult = 2; //bus 四分频 uint16 scldiv = bus_clk_khz * 1000 / ( (1< //需要从 ICR_2_SCL_divider 里找到 与最佳分频系数scldiv最相近的 分频系数 uint8 icr, n = 0x40; uint16 min_Dvalue = ~0, Dvalue; while(n) //循环里逐个扫描,找出最接近的 分频系数 { n--; Dvalue = abs(scldiv - ICR_2_SCL_divider[n]); if(Dvalue == 0) { icr = n; break; //退出while循环 } if(Dvalue < min_Dvalue) { icr = n; min_Dvalue = Dvalue; } } I2C_F_REG(I2CN[i2cn]) = ( 0 // I2C Frequency Divider register (I2CN_F) I2C分频寄存器 I2C最大波特率为 400k | I2C_F_MULT(mult) // 乘数因子 mul = 1< ); /* 使能 I2C */ I2C_C1_REG(I2CN[i2cn]) = ( 0 | I2C_C1_IICEN_MASK //使能I2C //| I2C_C1_IICIE_MASK //使能中断 ); return ( bus_clk_khz * 1000 / ( (1< /*! * @brief I2C通信结束后需要调用的函数函数 * @since v5.0 * @NOTE 如果通信失败,可尝试增大此延时值,确认是否延时导致的 */ void Pause(void) { u16 n; for(n = 1; n < 50000; n++) //注意,这个数据太小,会导致读取错误。 { asm("nop"); } } void i2c_StartTransmission (I2Cn_e i2cn, u8 SlaveID, MSmode Mode) { //ASSERT(Mode == MWSR || Mode == MRSW); //使用断言,检测 Mode 是否为 读 或 写 SlaveID = ( SlaveID << 1 ) | Mode ; //确定写地址和读地址 /* send start signal */ i2c_Start(i2cn); /* send ID with W/R bit */ i2c_write_byte(i2cn, SlaveID); } /*! * @brief 读取I2C设备指定地址寄存器的数据 * @param I2Cn_e I2C模块(I2C0、I2C1) * @param SlaveID 从机地址(7位地址) * @param reg 从机寄存器地址 * @return 读取的寄存器值 * @since v5.0 * Sample usage: uint8 value = i2c_read_reg(I2C0, 0x1D, 1); */ u8 i2c_read_reg(I2Cn_e i2cn, u8 SlaveID, u8 Addr) { u8 result; /* Send Slave Address */ i2c_StartTransmission (i2cn, SlaveID, MWSR); i2c_Wait(i2cn); /* Write Register Address */ i2c_write_byte(i2cn, Addr); i2c_Wait(i2cn); /* Do a repeated start */ i2c_RepeatedStart(i2cn); /* Send Slave Address */ i2c_write_byte(i2cn, ( SlaveID << 1) | MRSW ); i2c_Wait(i2cn); /* Put in Rx Mode */ i2c_PutinRxMode(i2cn); /* Turn off ACK since this is second to last byte being read*/ i2c_DisableAck(i2cn); //不应答 /* Dummy read 虚假读取*/ result = I2C_D_REG(I2CN[i2cn]); i2c_Wait(i2cn); /* Send stop since about to read last byte */ i2c_Stop(i2cn); /* Read byte */ result = I2C_D_REG(I2CN[i2cn]); return result; } /*! * @brief 写入一个字节数据到I2C设备指定寄存器地址 * @param I2Cn_e I2C模块(I2C0、I2C1) * @param SlaveID 从机地址(7位地址) * @param reg 从机寄存器地址 * @param Data 数据 * @since v5.0 * Sample usage: i2c_write_reg(I2C0, 0x1D, 1,2); //向从机0x1D 的寄存器 1 写入数据 2 */ void i2c_write_reg(I2Cn_e i2cn, u8 SlaveID, u8 Addr, u8 Data) { /* send data to slave */ i2c_StartTransmission(i2cn, SlaveID, MWSR); //启动传输 i2c_Wait(i2cn); i2c_write_byte(i2cn, Addr); //写地址 i2c_Wait(i2cn); i2c_write_byte(i2cn, Data); //写数据 i2c_Wait(i2cn); i2c_Stop(i2cn); Pause(); //延时太短的话,可能写出错 } char txt[20]; int b=3; int main() { #define ADDR 0x00 u8 i = 0; u8 Data=0; UART_Init(UART0,9600); //初始化串口 LCD_Init(); //显示屏 i2c_init(I2C0,400 * 1000); //初始化i2c0 while(1) { for(i=0;i<2;i++) { i2c_write_reg(I2C0, AT24C02_i2c_ADDRESS, ADDR, 1); //i2c向AT24C02_i2c_ADDRESS芯片写入数据 i 到地址为ADDR的寄存器 DelayMs(50); Data = i2c_read_reg(I2C0,AT24C02_i2c_ADDRESS, ADDR); DelayMs(50); printf("接收到的数据为:%dnn", Data); //蓝牙发送数据 sprintf(txt,"A=%d",Data); LCD_P6x8Str(0,0,(uint8*)txt); //oled屏显示数据 } } } |
|
相关推荐
1个回答
|
|
帮忙顶一下,坐等大神解答
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-LCD显示图片编程示例之介绍mmap
238 浏览 0 评论
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
629 浏览 0 评论
【RA-Eco-RA2E1-48PIN-V1.0开发板试用】(第三篇)ADC采集+PWM输出
552 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十五章 人脸识别实验
552 浏览 0 评论
1074 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11763 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 22:31 , Processed in 0.509009 second(s), Total 77, Slave 56 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号