|
本帖最后由 L.fish 于 2010-7-29 15:47 编辑
[注:本文源自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
written by L.fish |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|