打印

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

[复制链接]
2664|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

#include "iic.h"
#include "myfun.h"

/*******************************************************

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

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

/******************************************************************
- 功能描述:IIC启动
- 隶属模块:IIC模块
- 函数属性:外部,供用户使用
- 参数说明:无      
- 返回说明:无
- 注:无
******************************************************************/

void IIC_Start()
{
SDA=1;
delay(IIC_DelayTime);
SCL=1;
delay(IIC_DelayTime);
SDA=0;
delay(IIC_DelayTime);
SCL=0;
delay(IIC_DelayTime);
}

/******************************************************************
- 功能描述:IIC结束
- 隶属模块:IIC模块
- 函数属性:外部,供用户使用
- 参数说明:无      
- 返回说明:无
- 注:无
******************************************************************/

void IIC_Stop()  
{
SDA=0;
delay(IIC_DelayTime);
SCL=1;
delay(IIC_DelayTime);
SDA=1;
delay(IIC_DelayTime);
SCL=0;
delay(IIC_DelayTime);
}

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

void IIC_Ack()
{
SDA=0;
delay(IIC_DelayTime);
SCL=1;
delay(IIC_DelayTime);
SCL=0;
delay(IIC_DelayTime);
}

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

void IIC_NAck()
{
SDA=1;
delay(IIC_DelayTime);
SCL=1;
delay(IIC_DelayTime);
SCL=0;
delay(IIC_DelayTime);
}

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

bit IIC_Get_Ack()
{
bit ErrorBit;
SDA=1;
delay(IIC_DelayTime);
SCL=1;
delay(IIC_DelayTime);
ErrorBit=SDA;
delay(IIC_DelayTime);
SCL=0;
delay(IIC_DelayTime);
return ErrorBit;
}

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

unsigned char IIC_Write_Byte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
  SDA=((dat<<i)&0x80);  
  SCL=1;
  delay(IIC_DelayTime);
  SCL=0;
  delay(IIC_DelayTime);
}
return IIC_Get_Ack();
}

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

unsigned char IIC_Read_Byte()
{
unsigned char i,rbyte=0;
SDA=1;
for(i=0;i<8;i++)
{
  SCL=1;
  delay(IIC_DelayTime);
  if(SDA) rbyte|=(0x80>>i);
  delay(IIC_DelayTime);
  SCL=0;
  delay(IIC_DelayTime);
}
return rbyte;
}
iic.h

#ifndef _IIC_H_
#define _IIC_H_

/*******************************************************

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

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

#include <reg51.h>

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

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

void IIC_Start();
void IIC_Stop();
void IIC_Ack();
void IIC_NAck();
bit IIC_Get_Ack();
unsigned char IIC_Write_Byte(unsigned char dat);
unsigned char IIC_Read_Byte();

#endif

使用特权

评论回复
板凳
tktcy|  楼主 | 2009-12-18 15:55 | 只看该作者
和我的好像差不太多呀.但是我的还是没有显示呀...啊啊啊..为什么为什么?:'(:'(
这个I2C我学了两周了,还是调不通呀..我修改了一下,我看不一样的地方也就是我的移位方向和上面的是不一样的.我把它改成上面那种方式了.

使用特权

评论回复
地板
znmcu| | 2009-12-18 16:21 | 只看该作者
这个IIC程序模块是我写的,应用在PCF8563   AT24C64上都没有问题,你仔细查一下你的程序

使用特权

评论回复
5
tktcy|  楼主 | 2009-12-18 16:30 | 只看该作者
嗯,我再查查,整不明白什么原因..

使用特权

评论回复
6
znmcu| | 2009-12-18 16:45 | 只看该作者
建议采样层次化,模块化的工程代码组织方法,代码会清晰很多

使用特权

评论回复
7
tktcy|  楼主 | 2009-12-18 19:30 | 只看该作者
嗯,其实我是想这样的,再说这本来其实就是一个模块程序,单I2C的.拿液晶来试的.原来我写的时候,是先把每段什么功能先做了一个层次结构,后来改多了,改乱了.以后我会注意的,谢谢.

使用特权

评论回复
8
hotpower| | 2009-12-19 05:34 | 只看该作者
I2C只要是ACK的问题,在此问题上多下点功夫即可。

http://www.baigoogledu.com/search.php?hl=zh-CN&q=I2C+twi+smbus+hotpower

使用特权

评论回复
9
工大第二枪| | 2009-12-19 19:50 | 只看该作者
LZ,先用示波器,量一下IIC的波形,先看看ACK有没有出来。

使用特权

评论回复
10
tktcy|  楼主 | 2009-12-20 13:13 | 只看该作者
好吧,看来我非得去借个示波器来看看了.

使用特权

评论回复
11
tktcy|  楼主 | 2009-12-21 15:07 | 只看该作者
问题找到了,谢谢各位,我问题是移位方向移错了..应该是从高位开始移,我是从低位走了..这个驱动芯片,它从地址发送后,必须至少跟1byte的命令,而命令的定义方式,必须是第一位为1,从低位开始移,则出现了第1位不是1的情况,于是,收不到ACK..现在显示已经出来了,只是又遇到了新问题,程序运行时只显示最上面的六个短横,和下面的小数点.只有程序运行到结束时,让它停下来.才会显示出要显示的数据来.六个8.不明就理中..

使用特权

评论回复
12
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);
}

使用特权

评论回复
13
andy2003hu| | 2009-12-21 16:02 | 只看该作者
8# hotpower
菜农发的这个网址有意思。哈哈

使用特权

评论回复
14
tktcy|  楼主 | 2009-12-22 09:54 | 只看该作者
灌水,出去站半个小时军姿再回来..
显示问题解决了,程序结束周期太短导致的..
谢谢各位.

使用特权

评论回复
15
gpzmvp| | 2013-6-24 17:28 | 只看该作者
mark一下 回头过来看看!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

17

帖子

1

粉丝