本帖最后由 L.fish 于 2010-7-29 15:47 编辑
本人尊重原文作者,这篇文章非本人原创,feibit论坛是个不错的论坛,希望大家多看看这个网站。 [注:本文源自www.feibit.com--“飞比”Zigbee论坛,如需转载请保留此行] 近来为了做一个加速度传感器的项目,其中用到了无线模块由于英明神武的老板决定用ZigBee来做传输 结果就跑出了一些列的问题 其中一个就是MXC6202加速度传感器传输的数据用到了IIC协议 要用CC2430来做IIC的模拟 因为摸过了一段时间的CC2430,知道其中还是51的内核 以为是很简单的东西,应该和atmel的8051差不多的 但是做的时候又碰到了一系列的问题 最后绕了一圈才发现,哦,原来如此 2430芯片和51其中一个很大的区别就是: 必须人为的设置IO口的输入输出方向 也就是要设置每个端口的pin脚的PXDIR是1还是0 说还是太空泛了,那就上程序吧...... 和51的程序相比,其实大部分还是相同的,我在这里就主要讲解一下两者不同的地方 只能算作一个平台的移植吧.... 源程序会附在后面 SDA和SCL的读写 其实IIC总线协议的实现就是控制这两根线,让数据在规定的时候进行传输 其中就要最主要的就是对SCL的写操作和SDA的读写 以下是i2c_1.c的源程序,讲解就穿插其中..... //i2c_1.c #include "ioCC2430.h" #include "i2c.h" #define TRUE 1 #define FALSE 0 /*我的管脚定义是 SDA定义为P1.5 SCL定义为P1.4 */ #define SCL P1_4 #define SDA P1_5 /* 一个nop就是一条机器指令周期 = 1/32MHz 那32个nop就是1us啦 ----这里是outman给我做出的讲解,在此再作感谢 */ void Delay_1u(unsigned int microSecs) { while(microSecs--) { /* 32 NOPs == 1 usecs */ asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); } } unsigned char error; /*错误提示,全局变量*/ /* 当通过CC2430的IO端口往外面写数据的时候 必须将对应的IO端口数据方向设置为输出 CC2430中DIRPX_Y为1时IO口为输出功能 DIRPX_Y为0时IO口为输入功能 我的SDA是P1.5,则SDA为输出功能时 P1口DIR应该是0010 0000 即0x20,其他可以依次类推...... 啰嗦完毕,继续程序.... */ void WriteSDA1(void)//SDA 输出1,相当于51里面的SDA=1 { P1DIR |= 0x20; SDA = 1; } void WriteSDA0(void)//SDA 输出0 { P1DIR |= 0x20; SDA = 0; } void WriteSCL1(void)//SCL 输出1 { P1DIR |= 0x10; SCL = 1; } void WriteSCL0(void)//SCL 输出1 { P1DIR |= 0x10; SCL = 0; } void ReadSDA(void)//这里设置SDA对应IO口DIR可以接收数据 { P1DIR &= 0xDF; } /*启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变*/ void I2C_Start_1(void) { WriteSDA1(); WriteSCL1(); Delay_1u(50); WriteSDA0(); Delay_1u(50); WriteSCL0(); Delay_1u(50); } /*终止I2C总线,当SCL为高电平时使SDA产生一个正跳变*/ void I2C_Stop_1(void) { WriteSDA0(); Delay_1u(50); WriteSCL1(); Delay_1u(50); WriteSDA1(); Delay_1u(50); WriteSCL0(); Delay_1u(50); } /*发送0,在SCL为高电平时使SDA信号为低*/ void SEND_0_1(void) /* SEND ACK */ { WriteSDA0(); WriteSCL1(); Delay_1u(50); WriteSCL0(); Delay_1u(50); } /*发送1,在SCL为高电平时使SDA信号为高*/ void SEND_1_1(void) { WriteSDA1(); WriteSCL1(); Delay_1u(50); WriteSCL0(); Delay_1u(50); } /*发送完一个字节后检验设备的应答信号*/ char Check_Acknowledge_1(void) { WriteSDA1(); WriteSCL1(); Delay_1u(50); F0=SDA; Delay_1u(50); WriteSCL0(); Delay_1u(50); if(F0==1) return FALSE; return TRUE; } void Write_Acknowledge_1(void) { WriteSDA0(); Delay_1u(50); WriteSCL1(); Delay_1u(50); WriteSCL0(); Delay_1u(50); } /*向I2C总线写一个字节*/ void WriteI2CByte_1(char b) { char i; for(i=0;i<8;i++) { if((b<<i)&0x80) { SEND_1_1(); } else { SEND_0_1(); } } } /*从I2C总线读一个字节*/ char ReadI2CByte_1(void) { char b=0,i; WriteSDA1(); for(i=0;i<8;i++) { WriteSCL0(); Delay_1u(50); WriteSCL1(); Delay_1u(50); ReadSDA(); F0=SDA;//寄存器中的一位,用于存储SDA中的一位数据 if(F0==1) { b=b<<1; b=b|0x01; } else b=b<<1; } WriteSCL0(); return b; } PS: 这里没有重要讲解IIC的实现原理 比如什么时候发送1,什么时候发送0 这里主要是讲解了一下在移植过程中需要注意的问题 如果有什么问题再问吧 整理一下需要注意的: 1.需要手动设置IO方向 2.延时设定的方式和晶振是有关系的,需要多长时间可以参照前面的程序 程序参考过robin's evolution的那篇用cc2430读取AT24CXX的驱动程序文章 以及感谢群里的on the way给我耐心讲解51的IIC ![]() 最后还是要感谢一下outman,谢谢你的提醒 ![]() over |