查看: 18821|回复: 23

[0o原创]CC2430模拟IIC的数据读取

[复制链接]
L.fish 发表于 2010-7-29 10:57:52 | 显示全部楼层 |阅读模式
本帖最后由 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
outman 发表于 2010-7-29 11:22:30 | 显示全部楼层
感谢小鱼的无私奉献,文章写得也简洁易懂。在不涉及商业机密的前提下,如果大家都有共享的精神,相信每个人都会从中受益的
xingqing 发表于 2010-7-29 13:14:23 | 显示全部楼层
顶下你 小鱼  哈哈
ttxs 发表于 2010-7-30 12:51:10 | 显示全部楼层
这么有用的东东~~~
楼主真是好人,收藏了,以后肯定用得上
sendoc 发表于 2010-8-6 08:19:10 | 显示全部楼层
好东西,继续关注。什么时候我也来一帖
outman 发表于 2010-8-6 13:04:06 | 显示全部楼层
期待sendoc的大作,论坛正需要这样的原创文章。
百事可乐 发表于 2010-8-6 19:52:39 | 显示全部楼层
怎么整,怎么整,我也想发发
百事可乐 发表于 2010-8-6 19:53:18 | 显示全部楼层
开始学习论坛的每个原创帖子
longerwell 发表于 2010-8-18 09:48:32 | 显示全部楼层
感谢楼主的无私奉献
li359700725 发表于 2010-12-3 16:11:29 | 显示全部楼层
呵呵。。好东西值得的学习啦
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表