| 本帖最後由 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 |