linux 下 i2c 的驱动 以及 与时钟芯片 pcf8563之间的通信(二)
2012/7/10 linux下i2c驱动与通信(二) by:韩大卫 @吉林师范大学 在i2c-test的基础上, 使用i2c与Pcf8563通信,通过发送和接收数据,对rtc芯片进行set 和get操作。 既然是操作时间,可以使用struct rtc_time, 定义如下: struct rtc_time { int tm_sec; int tm_min; int tm_hour; int tm_mday; } 在pcf8563_get_datetime() 中: struct i2c_msg msgs[] = { { client->addr, 0, 1, buf }, /* setup read ptr */ { client->addr, I2C_M_RD, 13, buf }, /* read status + date */ }; 定义了两个msg, 在i2c-octeon 中分别进入了 ret = octeon_i2c_simple_write() ret = octeon_i2c_read() 进入simple_write()作用是将第一个buf 即offset 写入寄存器,这样在read函数即可直接读此寄存器。 2012.7.11 .14:50 出现这样一个问题: root@juson:/han# ./i2c-test strlen(buf) = 1 buf[0] = 8 root@juson:/han# ./i2c-test -r strlen(buf) = 1 buf[0] = 8 root@juson:/han# ./i2c-test -l 2012年 07月 11日 星期三 21:49:41 root@juson:/han# ./i2c-test strlen(buf) = 13 buf[0] = 8 buf[1] = 40 buf[2] = 43 buf[3] = 49 buf[4] = 21 buf[5] = 11 buf[6] = 3 buf[7] = 7 buf[8] = 12 buf[9] = a0 buf[10] = 84 buf[11] = b2 buf[12] = b5 有少两情况下会出现strlen(buf) = 13 过一会: root@juson:/han# ./i2c-test strlen(buf) = 13 buf[0] = 8 buf[1] = 40 buf[2] = 54 buf[3] = 53 buf[4] = 21 buf[5] = 11 buf[6] = 3 buf[7] = 7 buf[8] = 12 buf[9] = a0 buf[10] = 84 buf[11] = b2 buf[12] = b5 root@juson:/han# ./i2c-test strlen(buf) = 13 buf[0] = 8 buf[1] = 40 buf[2] = 55 buf[3] = 53 buf[4] = 21 buf[5] = 11 buf[6] = 3 buf[7] = 7 buf[8] = 12 buf[9] = a0 buf[10] = 84 buf[11] = b2 buf[12] = b5 这次是全部是root@juson:/han# ./i2c-test strlen(buf) =13 的情况。 代码中: for(i = 0; i< strlen(buf); i++) printf("buf[%d] = %x\n",i,buf[i]); 本意是想看经过read_data(addr, offset, buf) 后, buf中成员有多少被赋值了,但忘记了一个地方: strlen(buf) 这个函数是遇到buf中的0,或者'\0' 就截止的,恰好 第二个寄存器01h control_status 的值有时候恰好为0x0,或者0x40,这样,当为0x0时候strlen(buf) 就为1了。 01h control_status_2 0 0 STOP 0 TESTC 0 0 0 改为 for(i = 0; i< 13; i++) printf("buf[%d] = %x\n",i,buf[i]); 可以看出,strlen(buf) = 13 buf[0] = 8 buf[1] = 40 buf[2] = 43 buf[3] = 15 buf[4] = 22 buf[5] = 11 buf[6] = 3 buf[7] = 7 buf[8] = 12 buf[9] = a0 buf[10] = 84 buf[11] = b2 buf[12] = b5 另一种情况: strlen(buf) = 1 buf[0] = 8 buf[1] = 0 buf[2] = 39 buf[3] = 15 buf[4] = 22 buf[5] = 11 buf[6] = 3 buf[7] = 7 buf[8] = 12 buf[9] = a0 buf[10] = 84 buf[11] = b2 buf[12] = b5 这时候strlen就出现了让人迷惑的显示! 15:50 。出现了段错误: 这条语句: tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F); 52 /* 53 tm->tm_min = buf[PCF8563_REG_MN] & 0x7F; 54 tm->tm_hour = buf[PCF8563_REG_HR] & 0x3F; // rtc hr 0-23 55 tm->tm_mday = buf[PCF8563_REG_DM] & 0x3F; tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F); 检查了struct rtc_time{ 成员都是对的。怎么会段错误。 肯定的指针的问题。 struct rtc_time *tm; tm->tm_min = buf[PCF8563_REG_MN] & 0x7F; tm->tm_hour = buf[PCF8563_REG_HR] & 0x3F; // rtc hr 0-23 tm->tm_mday = buf[PCF8563_REG_DM] & 0x3F; 平时运行的时候都没有出现问题,但本身是有问题的。 错误原因: *tm 本身是野指针 ! 定义了这个指针后:要用malloc 对tm 进行分配内存。 struct rtc_time *tm = (struct rtc_time*)malloc(sizeof(struct rtc_time)); 总结: 使用指针时候,一定要谨慎! 一定要先malloc, 再对其内容操作! 17:39 另一个问题: unsigned char data; data 最大只能存255, 256就是0了。 那么 write_data(0x51,0x08,data) 的时候, 年份不能直接传给data,否则会溢出。 就是2012:07:11 时候,如果将2012直接赋值给data,那么会产生溢出,data不会是原来的值。 2012 的bin是: 11111011100 unsigned char data 之能保存8bit, 1101 1100 十进制是220。 怎么办: 先参考pcf8563_set_datetime。中的代码: unsigned char buf[9]; /* hours, minutes and seconds */ buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec); buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min); buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour); buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday); /* month, 1 - 12 */ buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1); /* year and century */ buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100); if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100)) buf[PCF8563_REG_MO] |= PCF8563_MO_C; buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100); %100, 就可以把最后的8bit取得。 if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100)) buf[PCF8563_REG_MO] |= PCF8563_MO_C; 这样把PCF8563_REG_MO的 PCF8563_MO_C bit 决定是否置位。 2012.7.12 一个新的小问题: if(*(ptr+2) == ':'){ tm->tm_hour = atoi(ptr); tm->tm_min = atoi(ptr + 3); tm->tm_sec = atoi(ptr + 6); } else if(*(ptr+4) == ':'){ tm->tm_year = atoi(ptr); tm->tm_mon = atoi(ptr + 5); tm->tm_mday = atoi(ptr + 8); if(*(ptr+10) == '-'){ tm->tm_hour = atoi(ptr + 11); tm->tm_min = atoi(ptr + 14); tm->tm_sec = atoi(ptr + 17);