嘿嘿..我又来了,又出问题了,各路大侠过来帮忙了..I2C学习

[复制链接]
4208|14
 楼主| tktcy 发表于 2009-12-18 15:35 | 显示全部楼层 |阅读模式
I2C不动,不晓得哪里错了..我是用I2C来写BU9793段码管驱动芯片的数据.但是调不出来了.先前的时候,可能优化等级较高,优化掉了我发送数据的一部分程序.
说到底芯片的I2C还是有些迷糊,先帮我看下这个程序,看是哪里出了错,茫茫然看DATASHEET有点迷糊,弄出来一次,就有直观的认识了.谢谢各位喽.
噢,对了,CPU是C8051F310

//LCD.c
#include <C8051F310.h>
#include <intrins.h>
#include <STRING.h>
///////////////////////////////////////
//位声明.
//////////////////////////////////////
bit ack;
sbit sda = P0^5;
sbit scl = P0^4;
int i;
///////////////////////////////////////
//字
////////////////////////////////////////
static  WORD_0[] = {0X7D,0X60,0X5B,0X7A,0X66,0X3E,0X3F,0X68,0X7F,0X7E};
/////////////////////////////////////
//函数声明
////////////////////////////////////
void delay4(void);
void delay2(void);
void start(void);
void stop(void);
void slave_add(void);
void send_data(int);
void send1(int);
bit test_ack(void);
////////////////////////////////////
//函数
///////////////////////////////////
void main(void)
{
///////////////////////////////////
//初始设置
//////////////////////////////////
    int a[11],q=0,c;
OSCICN = 0xc3;  /*8分频*/
OSCXCN = 0x07;      /*选用外部晶振参数*/
CLKSEL = 0x00;  /*选取用内部晶振*/
RSTSRC = 0x02;  /*上电复位*/
XBR0 = 0x00;
XBR1 = 0x70;  /*交叉开关1*/
P0SKIP = 0x18;
P0MDIN = 0xFF;
P0MDOUT = 0x02;
P1SKIP = 0x00;  /*1为跳,0为数字口*/
P1MDIN =0xFF;  /*0为模拟输入,1为数字输入*/
P1MDOUT = 0xFF;  /*0为漏极开路输出,1为推挽式输出.*/
TCON = 0x10;  //定时器0允许,/INT0边沿触发。
TMOD = 0x02;  //0x00000010;定时器/计数器工作方式。选为0。CKCON。3定义的时钟加1。
CKCON = 0x01;  //00000101 T3=FC/12----T2定时器为内部时钟;T1,T0时钟为系统频率分频数4----T0为系统时钟。
PCA0MD = 0x00;  //禁止WDT和PCA时钟源
for(i=0;i<12;i++)
  a[i] = 8;
/////////////////////////////////
//数据发送等调用
/////////////////////////////////
for(i=0;i<10;i++)
{
  q = a[i];
  sda = 1;
  delay4();
  delay2();
  scl = 1;
  for(c=0;c<100;c++)
   _nop_();
  stop();
  start();
  slave_add();
  send_data(q);
  send1(q);
  while(test_ack());
  stop();
}
}
/////////////////////////////////
//开始
/////////////////////////////////
void start(void)
{
sda = 1;
delay4();
scl = 1;
delay4();
delay4();
sda = 0;
delay4();
delay4();
scl = 0;
delay2();
delay4();
}
void delay2()
{
_nop_();
_nop_();
}
void delay4()
{
_nop_();
_nop_();
_nop_();
_nop_();
}
/////////////////////////////////
//从地址
/////////////////////////////////
void slave_add(void)
{
unsigned char p;
p = 0x7C;
send1(p);
while(test_ack());
p = 0xEA;
send1(p);
while(test_ack());
p = 0xF0;
send1(p);
while(test_ack());
p = 0xA2;
send1(p);
while(test_ack());
p = 0xE8;
send1(p);
while(test_ack());
p = 0x00;
send1(p);
while(test_ack());
}
////////////////////////////////
//显示数据发送
/////////////////////////////////
void send1(q)
{
int d;
unsigned char a;
b;
a = q;
for(d=0;d<=7;d++)
{
  b = a&01;
  if(b==1)
  {
   delay4();
   delay2();
   sda = 1;
   delay4();
   delay4();
   _nop_();
   scl = 1;
   delay4();
   delay4();
   scl = 0;
   delay4();
   delay2();
   sda = 0;
   delay4();
   delay2();
  }
  if(b==0)
  {
   delay4();
   delay2();
   sda = 0;
   delay4();
   scl = 1;
   delay4();
   delay4();
   scl = 0;
   delay4();
   delay2();
   sda = 0;
   delay4();
   delay2();
  }
  a >>= 1;
}
}
///////////////////////////////
//结束
///////////////////////////////
void stop()
{
delay4();
delay2();
scl = 0;
delay4();
sda = 0;
delay4();
scl = 1;
delay4();
sda = 0;
delay4();
}
bit test_ack(void)
{
bit errorbit;
sda = 0;
delay4();
scl = 1;
delay4();
errorbit = sda;
scl = 0;
delay4();
return(errorbit);
}
znmcu 发表于 2009-12-18 15:38 | 显示全部楼层
iic.c

  1. #include "iic.h"
  2. #include "myfun.h"

  3. /*******************************************************

  4.         +-------------------------------------+
  5.         | 振南电子 驱动程序模块   IIC  部分   |
  6.         +-------------------------------------+

  7.   此源码版权属 振南 全权享有,如欲引用,敬请署名并告知
  8.         严禁随意用于商业目的,违者必究,后果自负
  9.          振南电子
  10.              ->产品网站 http://www.znmcu.cn/
  11.              ->产品网店 http://shop.znmcu.cn/
  12.              ->产品咨询 QQ:987582714
  13.                                     MSN:yzn07@126.com
  14.                             WW:yzn07       
  15.                                                                           
  16. ********************************************************/

  17. /******************************************************************
  18. - 功能描述:IIC启动
  19. - 隶属模块:IIC模块
  20. - 函数属性:外部,供用户使用
  21. - 参数说明:无      
  22. - 返回说明:无
  23. - 注:无
  24. ******************************************************************/

  25. void IIC_Start()
  26. {
  27. SDA=1;
  28. delay(IIC_DelayTime);
  29. SCL=1;
  30. delay(IIC_DelayTime);
  31. SDA=0;
  32. delay(IIC_DelayTime);
  33. SCL=0;
  34. delay(IIC_DelayTime);
  35. }

  36. /******************************************************************
  37. - 功能描述:IIC结束
  38. - 隶属模块:IIC模块
  39. - 函数属性:外部,供用户使用
  40. - 参数说明:无      
  41. - 返回说明:无
  42. - 注:无
  43. ******************************************************************/

  44. void IIC_Stop()  
  45. {
  46. SDA=0;
  47. delay(IIC_DelayTime);
  48. SCL=1;
  49. delay(IIC_DelayTime);
  50. SDA=1;
  51. delay(IIC_DelayTime);
  52. SCL=0;
  53. delay(IIC_DelayTime);
  54. }

  55. /*********************************************************************
  56. - 功能描述:主设备发出应答
  57. - 隶属模块:IIC模块
  58. - 函数属性:外部,供用户使用
  59. - 参数说明:无      
  60. - 返回说明:无
  61. - 注:主设备(比如单片机),从从设备(比如AT24C64)读取字节后,如果
  62.        要继续读取,就要给从设备一个ACK(即所谓的“应答”,数据位SDA为0)
  63. *********************************************************************/

  64. void IIC_Ack()
  65. {
  66. SDA=0;
  67. delay(IIC_DelayTime);
  68. SCL=1;
  69. delay(IIC_DelayTime);
  70. SCL=0;
  71. delay(IIC_DelayTime);
  72. }

  73. /*********************************************************************
  74. - 功能描述:主设备发出无应答
  75. - 隶属模块:IIC模块
  76. - 函数属性:外部,供用户使用
  77. - 参数说明:无      
  78. - 返回说明:无
  79. - 注:主设备(比如单片机),从从设备(比如AT24C64)读取字节后,如果不再
  80.        进行读取,就要给从设备一个NACK(即所谓的“无应答”,数据位SDA为1)
  81. *********************************************************************/

  82. void IIC_NAck()
  83. {
  84. SDA=1;
  85. delay(IIC_DelayTime);
  86. SCL=1;
  87. delay(IIC_DelayTime);
  88. SCL=0;
  89. delay(IIC_DelayTime);
  90. }

  91. /*********************************************************************
  92. - 功能描述:主设备检测从设备应答
  93. - 隶属模块:IIC模块
  94. - 函数属性:外部,供用户使用
  95. - 参数说明:无      
  96. - 返回说明:无
  97. - 注:主设备(比如单片机),向从设备(比如AT24C64)写入字节后,要检测从
  98.        设备发出的应答,如果数据位SDA为0,说明向从设备成功写入了字节
  99. *********************************************************************/

  100. bit IIC_Get_Ack()
  101. {
  102. bit ErrorBit;
  103. SDA=1;
  104. delay(IIC_DelayTime);
  105. SCL=1;
  106. delay(IIC_DelayTime);
  107. ErrorBit=SDA;
  108. delay(IIC_DelayTime);
  109. SCL=0;
  110. delay(IIC_DelayTime);
  111. return ErrorBit;
  112. }

  113. /*********************************************************************
  114. - 功能描述:主设备向从设备写入一字节
  115. - 隶属模块:IIC模块
  116. - 函数属性:外部,供用户使用
  117. - 参数说明:dat:将要写入的字节      
  118. - 返回说明:从设备的应答值
  119. - 注:向从设备写入一个字节,并返回从设备的应答值
  120. *********************************************************************/

  121. unsigned char IIC_Write_Byte(unsigned char dat)
  122. {
  123. unsigned char i;
  124. for(i=0;i<8;i++)
  125. {
  126.   SDA=((dat<<i)&0x80);  
  127.   SCL=1;
  128.   delay(IIC_DelayTime);
  129.   SCL=0;
  130.   delay(IIC_DelayTime);
  131. }
  132. return IIC_Get_Ack();
  133. }

  134. /*********************************************************************
  135. - 功能描述:主设备从从设备读取一字节
  136. - 隶属模块:IIC模块
  137. - 函数属性:外部,供用户使用
  138. - 参数说明:无     
  139. - 返回说明:读到的字节
  140. - 注:无
  141. *********************************************************************/

  142. unsigned char IIC_Read_Byte()
  143. {
  144. unsigned char i,rbyte=0;
  145. SDA=1;
  146. for(i=0;i<8;i++)
  147. {
  148.   SCL=1;
  149.   delay(IIC_DelayTime);
  150.   if(SDA) rbyte|=(0x80>>i);
  151.   delay(IIC_DelayTime);
  152.   SCL=0;
  153.   delay(IIC_DelayTime);
  154. }
  155. return rbyte;
  156. }
iic.h

  1. #ifndef _IIC_H_
  2. #define _IIC_H_

  3. /*******************************************************

  4.         +-------------------------------------+
  5.         | 振南电子 驱动程序模块   IIC  部分   |
  6.         +-------------------------------------+

  7.   此源码版权属 振南 全权享有,如欲引用,敬请署名并告知
  8.         严禁随意用于商业目的,违者必究,后果自负
  9.          振南电子
  10.              ->产品网站 http://www.znmcu.cn/
  11.              ->产品网店 http://shop.znmcu.cn/
  12.              ->产品咨询 QQ:987582714
  13.                                     MSN:yzn07@126.com
  14.                             WW:yzn07       
  15.                                                                           
  16. ********************************************************/

  17. #include <reg51.h>

  18. #define IIC_DelayTime 10 //IIC_DelayTime用于控制IIC的速度,有些器件速度太快会工作不正常
  19.                                       //可以调整IIC_DelayTime来降低IIC的速度

  20. sbit SCL=P3^6; //IIC的时钟线
  21. sbit SDA=P3^7; //IIC的数据线

  22. void IIC_Start();
  23. void IIC_Stop();
  24. void IIC_Ack();
  25. void IIC_NAck();
  26. bit IIC_Get_Ack();
  27. unsigned char IIC_Write_Byte(unsigned char dat);
  28. unsigned char IIC_Read_Byte();

  29. #endif
 楼主| tktcy 发表于 2009-12-18 15:55 | 显示全部楼层
和我的好像差不太多呀.但是我的还是没有显示呀...啊啊啊..为什么为什么?:'(:'(
这个I2C我学了两周了,还是调不通呀..我修改了一下,我看不一样的地方也就是我的移位方向和上面的是不一样的.我把它改成上面那种方式了.
znmcu 发表于 2009-12-18 16:21 | 显示全部楼层
这个IIC程序模块是我写的,应用在PCF8563   AT24C64上都没有问题,你仔细查一下你的程序
 楼主| tktcy 发表于 2009-12-18 16:30 | 显示全部楼层
嗯,我再查查,整不明白什么原因..
znmcu 发表于 2009-12-18 16:45 | 显示全部楼层
建议采样层次化,模块化的工程代码组织方法,代码会清晰很多
 楼主| tktcy 发表于 2009-12-18 19:30 | 显示全部楼层
嗯,其实我是想这样的,再说这本来其实就是一个模块程序,单I2C的.拿液晶来试的.原来我写的时候,是先把每段什么功能先做了一个层次结构,后来改多了,改乱了.以后我会注意的,谢谢.
hotpower 发表于 2009-12-19 05:34 | 显示全部楼层
I2C只要是ACK的问题,在此问题上多下点功夫即可。

http://www.baigoogledu.com/search.php?hl=zh-CN&q=I2C+twi+smbus+hotpower
工大第二枪 发表于 2009-12-19 19:50 | 显示全部楼层
LZ,先用示波器,量一下IIC的波形,先看看ACK有没有出来。
 楼主| tktcy 发表于 2009-12-20 13:13 | 显示全部楼层
好吧,看来我非得去借个示波器来看看了.
 楼主| tktcy 发表于 2009-12-21 15:07 | 显示全部楼层
问题找到了,谢谢各位,我问题是移位方向移错了..应该是从高位开始移,我是从低位走了..这个驱动芯片,它从地址发送后,必须至少跟1byte的命令,而命令的定义方式,必须是第一位为1,从低位开始移,则出现了第1位不是1的情况,于是,收不到ACK..现在显示已经出来了,只是又遇到了新问题,程序运行时只显示最上面的六个短横,和下面的小数点.只有程序运行到结束时,让它停下来.才会显示出要显示的数据来.六个8.不明就理中..
 楼主| tktcy 发表于 2009-12-21 15:34 | 显示全部楼层
噢,对了,各位,我把修改后的程序发来看下吧,还不晓得是什么原因导致运行中不显示的.有空的帮我看下吧,谢谢..


//LCD.c
#include <C8051F310.h>
#include <intrins.h>
#include <STRING.h>

///////////////////////////////////////

//位声明.

//////////////////////////////////////

bit ack;
sbit sda = P0^5;
sbit scl = P0^4;
int i;

///////////////////////////////////////
//字
////////////////////////////////////////

static  WORD_0[] = {0X7D,0X60,0X5B,0X7A,0X66,0X3E,0X3F,0X68,0X7F,0X7E};

/////////////////////////////////////

//函数声明

////////////////////////////////////

void delay4(void);
void delay2(void);
void start(void);
void stop(void);
void slave_add(void);
void send_data(int);
void send1(int);
bit test_ack(void);

////////////////////////////////////
//函数
///////////////////////////////////
void main(void)
{
///////////////////////////////////
//初始设置
//////////////////////////////////

    int a[11],q=0;
        OSCICN = 0xc3;                /*8分频*/
        OSCXCN = 0x07;      /*选用外部晶振参数*/
        CLKSEL = 0x00;                /*选取用内部晶振*/
        RSTSRC = 0x02;                /*上电复位*/
        XBR0 = 0x00;
        XBR1 = 0x70;                /*交叉开关1*/
        P0SKIP = 0x18;
        P0MDIN = 0xFF;
        P0MDOUT = 0x02;
        P1SKIP = 0x00;                /*1为跳,0为数字口*/
        P1MDIN =0xFF;                /*0为模拟输入,1为数字输入*/
        P1MDOUT = 0xFF;                /*0为漏极开路输出,1为推挽式输出.*/
        TCON = 0x10;                //定时器0允许,/INT0边沿触发。
        TMOD = 0x02;                //0x00000010;定时器/计数器工作方式。选为0。CKCON。3定义的时钟加1。
        CKCON = 0x01;                //00000101 T3=FC/12----T2定时器为内部时钟;T1,T0时钟为系统频率分频数4----T0为系统时钟。
        PCA0MD = 0x00;                //禁止WDT和PCA时钟源
        for(i=0;i<11;i++)
                a[i] = 5;
/////////////////////////////////
//数据发送等调用
/////////////////////////////////

        start();
        slave_add();
        for(i=0;i<11;i++)
        {
                q = a[i];
                q = WORD_0[q];
                send1(q);
                while(test_ack());
        }
        stop();
        start();
        q = 0x7C;
        send1(q);
        while(test_ack());
        q = 0xC8;
        send1(q);
        while(test_ack());
        stop();
       
        for(i=0;i<100;i++)
                _nop_();
       
}
/////////////////////////////////
//开始
/////////////////////////////////

void start(void)
{
        sda = 1;
        delay4();
        scl = 1;
        delay4();
        delay4();
        sda = 0;
        delay4();
        delay4();
        scl = 0;
        delay2();
        delay4();
}
void delay2()
{
        _nop_();
        _nop_();
}
void delay4()
{
        _nop_();
        _nop_();
        _nop_();
        _nop_();
}
/////////////////////////////////
//从地址
/////////////////////////////////
void slave_add(void)
{
        unsigned char p;
        p = 0x7C;//从地址
        send1(p);
        while(test_ack());
        p = 0xEA;//ICSET
        send1(p);
        while(test_ack());
        p = 0xF0;//BLKCTL
        send1(p);
        while(test_ack());
        p = 0xA2;//DISCTL
        send1(p);
        while(test_ack());
//        p = 0xE8;//ICSET
//        send1(p);
//        while(test_ack());
        p = 0x00;//ADSS
        send1(p);
        while(test_ack());
        //MDSET
}
////////////////////////////////
//显示数据发送
/////////////////////////////////
void send1(q)
{
        int d;       
        for(d=0;d<=7;d++)
        {
                sda=((q<<d)&0x80);  
                delay4();
                delay4();
                _nop_();
                scl = 1;
                delay4();
                delay4();
                scl = 0;
                delay4();
                delay2();
        }
}
///////////////////////////////
//结束
///////////////////////////////

void stop()
{
        delay4();
        sda = 0;
        delay4();
        scl = 1;
        delay4();
        delay4();
        sda = 1;
        delay4();
        scl = 0;
        delay4();
}
bit test_ack(void)
{
        bit errorbit;
        sda = 1;
        delay4();
        scl = 1;
        delay4();
        errorbit = sda;
        scl = 0;
        delay4();
        return(errorbit);
}
andy2003hu 发表于 2009-12-21 16:02 | 显示全部楼层
8# hotpower
菜农发的这个网址有意思。哈哈
 楼主| tktcy 发表于 2009-12-22 09:54 | 显示全部楼层
灌水,出去站半个小时军姿再回来..
显示问题解决了,程序结束周期太短导致的..
谢谢各位.
gpzmvp 发表于 2013-6-24 17:28 | 显示全部楼层
mark一下 回头过来看看!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

17

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部