找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1669|回复: 1
收起左侧

STC12C5A60S2单片机IIC控制PCA9698扩展IO 不运行了?

[复制链接]
ID:958676 发表于 2021-8-3 18:25 | 显示全部楼层 |阅读模式
单片机源程序如下:
#include        "STC12C5A60S2.h"//主控芯片的头文件
/************************常用数据类型定义*************************/
#include <intrins.h>
/********************常用数据类型定义**********************/
#define u8  uint8_t
#define u16 uint16_t
#define u32 uint32_t
typedef unsigned char  uint8_t;
typedef unsigned int   uint16_t;
typedef unsigned long  uint32_t;
/*************************宏定义***************************/
//#define  _Nop()  _nop_()   //定义空指令
#define        PCA9698        0x40       //PCA9698地址
/*******************端口/引脚定义区域**********************/
sbit SDA=P3^7;            //模拟I2C数据传送位
sbit SCL=P3^6;            //模拟I2C时钟控制位
sbit BLUE=P4^6;
bit ack;                        //应答标志位
/*********************函数声明区域*************************/
void Delay_MS(u16 Count);                //毫秒延迟函数
void   _Nop();   //定义空指令
void Start_I2c(void);                 //IIC起动总线函数
void Stop_I2c(void);                  //IIC结束总线函数
void SendByte(u8 c);                  //IIC字节发送函数
u8 RcvByte(void);                     //IIC字节接收函数
void Ack_I2c(bit a);                  //IIC应答函数
bit ISendByte(u8 sla,u8 c);//向无子地址器件发送字节数据函数
bit ISendStr(u8 sla,u8 suba,u8 *s,u8 no);
//向有子地址器件发送多字节数据函数
bit IRcvByte(u8 sla,u8 *c);//向无子地址器件读字节数据函数
bit IRcvStr(u8 sla,u8 suba,u8 *s,u8 no);
//向有子地址器件接收多字节数据函数
//*********************主函数区域**************************/
void main(void)
{

        
  u8 All_ctrl[1]={0x80};
        //设置全组控制寄存器数组(这里为默认值)
        u8 Select_Mode[1]={0x12};
        //设置模式选择寄存器(这里配置为应答时输出改变 使能中断响应)
        u8 GPIO_H[1]={0xff};
        //设置I/O端口状态数组
        u8 GPIO_L[1]={0x00};
        //设置I/O端口状态数组
  //u8 In_array[1]={0x7f};
        //设置I/O某端口号为中断标志位
        Delay_MS(10);
        ISendStr(PCA9698,0X2A,Select_Mode,1);
        //配置模式选择寄存器地址0x2A
  ISendStr(PCA9698,0X29,All_ctrl,1);
        //配置全组控制寄存器地址0X29
  ISendStr(PCA9698,0X28,GPIO_H,1);
        //配置输出结构寄存器地址0X28(写入1为默认推挽,0为开漏),这里配置为推挽
        //ISendStr(PCA9698,0X23,In_array,1);
        //0X23为中断屏蔽地址寄存器,配置为使用PD8作为中断标志位
        //当PD8端口状态改变时中断发生,中断输出引脚In变低电平
  //配置I/0口寄存器(设置为输出/输入,A~D组地址为0X18~0X1C)
        ISendStr(PCA9698,0X18,GPIO_L,1);//配置A组I/O为输出
        ISendStr(PCA9698,0X19,GPIO_L,1);//配置B组I/O为输出
        ISendStr(PCA9698,0X1A,GPIO_L,1);//配置C组I/O为输出
        ISendStr(PCA9698,0X1B,GPIO_L,1);//配置D组I/O为输出
        ISendStr(PCA9698,0X1C,GPIO_L,1);//配置E组I/O为输出
        while(1)
        {
    //配置输出端口寄存器(设置输出相应的状态,A~E组端口的地址为0X08~0X0C)        
                Delay_MS(500);
                ISendStr(PCA9698,0X08,GPIO_L,1);//A推挽输出高电平
                ISendStr(PCA9698,0X09,GPIO_L,1);//B推挽输出高电平
                ISendStr(PCA9698,0X0a,GPIO_L,1);//C推挽输出高电平
          ISendStr(PCA9698,0X0b,GPIO_L,1);//D推挽输出高电平
                ISendStr(PCA9698,0X0c,GPIO_L,1);//E推挽输出高电平
                Delay_MS(500);//延迟闪烁
                ISendStr(PCA9698,0X08,GPIO_H,1);//A推挽输出低电平
                ISendStr(PCA9698,0X09,GPIO_H,1);//B推挽输出低电平
                ISendStr(PCA9698,0X0a,GPIO_H,1);//C推挽输出低电平
    ISendStr(PCA9698,0X0b,GPIO_H,1);//D推挽输出低电平
                ISendStr(PCA9698,0X0C,GPIO_H,1);//E推挽输出低电平
        }
}
//***************************************************************/
//起动总线函数Start_I2c(void),无形参,无返回值
//***************************************************************/
void Start_I2c(void)
{
        SDA=1;    //发送起始条件的数据信号
        _Nop();
        SCL=1;
        _Nop();   //起始条件建立时间大于4.7us,延时
        _Nop();
        _Nop();
        _Nop();
        _Nop();   
        SDA=0;    //发送起始信号
        _Nop();   //起始条件锁定时间大于4μs
        _Nop();
        _Nop();
        _Nop();
        _Nop();      
        SCL=0;   //钳住I2C总线,准备发送或接收数据
        _Nop();
        _Nop();
}               
//***************************************************************/
//结束总线函数 Stop_I2c(void),无形参,无返回值
//***************************************************************/
void Stop_I2c(void)
{
        SDA=0;   //发送结束条件的数据信号
        _Nop();  //发送结束条件的时钟信号
        SCL=1;   //结束条件建立时间大于4μs
        _Nop();
        _Nop();
        _Nop();
        _Nop();
        _Nop();
        SDA=1;   //发送I2C总线结束信号
        _Nop();
        _Nop();
        _Nop();
        _Nop();
}
//***************************************************************/
//IIC字节数据传送函数SendByte(u8 c),有形参c,无返回值
//***************************************************************/
void  SendByte(u8 c)
{
        u8 BitCnt;
        for(BitCnt=0;BitCnt<8;BitCnt++)
        {
                //要传送的数据长度为8位
                if((c<<BitCnt)&0x80)
                        SDA=1;     //判断发送位
                else  
                        SDA=0;               
                _Nop();
                SCL=1;      //置时钟线为高,通知被控器开始接收数据位
                _Nop();
                _Nop();     //保证时钟高电平周期大于4μs
                _Nop();
                _Nop();
                _Nop();         
                SCL=0;
        }
        _Nop();
        _Nop();
        SDA=1;        //8位发送完后释放数据线,准备接收应答位
        _Nop();
        _Nop();   
        SCL=1;
        _Nop();
        _Nop();
        _Nop();
        if(SDA==1)
                ack=0;     
        else
                ack=1;      //判断是否接收到应答信号
        SCL=0;
        _Nop();
        _Nop();
}
//***************************************************************/
//IIC字节数据接收函数RcvByte(void),无形参,有返回值retc
//***************************************************************/
u8  RcvByte(void)
{
        u8 retc;
        u8 BitCnt;
        retc=0;
        SDA=1;       //置数据线为输入方式
        for(BitCnt=0;BitCnt<8;BitCnt++)
        {
                _Nop();           
                SCL=0;           //置时钟线为低,准备接收数据位
                _Nop();
                _Nop();         //时钟低电平周期大于4.7μs
                _Nop();
                _Nop();
                _Nop();
                SCL=1;          //置时钟线为高使数据线上数据有效
                _Nop();
                _Nop();
                retc=retc<<1;
                if(SDA==1)
                        retc=retc+1; //读数据位,接收的数据位放入retc中
                _Nop();
                _Nop();
        }
        SCL=0;   
        _Nop();
        _Nop();
        return(retc);
}
//***************************************************************/
//IIC应答子函数Ack_I2c(bit a),有形参a,无返回值
//***************************************************************/
void Ack_I2c(bit a)
{
        if(a==0)
                SDA=0;     //在此发出应答或非应答信号
        else
                SDA=1;
        _Nop();
        _Nop();
        _Nop();      
        SCL=1;
        _Nop();
        _Nop();     //时钟低电平周期大于4μs
        _Nop();
        _Nop();
        _Nop();  
        SCL=0;     //清时钟线,钳住I2C总线以便继续接收*/
        _Nop();
        _Nop();   
}        
//***************************************************************/
//向无子地址器件发送字节数据函数 ISendByte(u8 sla,u8 c)
//有形参sla:地址;c:发送数据;无返回值
//***************************************************************/
bit ISendByte(u8 sla,u8 c)
{
        Start_I2c();         //启动总线
        SendByte(sla);       //发送器件地址
        if(ack==0)
                return(0);
        SendByte(c);         //发送数据
        if(ack==0)
                return(0);
        Stop_I2c();          //结束总线
        return(1);
}        
//***************************************************************/
//向有子地址器件发送多字节数据函数ISendStr(u8 sla,u8 suba,u8 *s,u8 no)
//有形参sla:地址;suba:子地址;*s:数据数组;no:字节个数;有返回值1
//***************************************************************/
bit ISendStr(u8 sla,u8 suba,u8 *s,u8 no)
{
        u8 i;
        
        Start_I2c();          //启动总线

        SendByte(sla);       //发送器件地址
        if(ack==0)
                return(0);

        SendByte(suba);      //发送器件子地址
        if(ack==0)
                return(0);
        
        for(i=0;i<no;i++)
        {   
                SendByte(*s);       //发送数据
                if(ack==0)return(0);
                s++;
        }
         
        Stop_I2c();          //结束总线
         
        return(1);
}        
//***************************************************************/
//向无子地址器件读字节数据函数IRcvByte(u8 sla,u8 *c)
//有形参sla:地址;suba:发送数据;*c:;有返回值1
//***************************************************************/
bit IRcvByte(u8 sla,u8 *c)
{
        Start_I2c();        //启动总线

        SendByte(sla+1);    //发送器件地址
        if(ack==0)
                return(0);

        *c=RcvByte();       //读取数据
        Ack_I2c(1);         //发送非就答位
        Stop_I2c();         //结束总线
        return(1);
}        
//***************************************************************/
//向有子地址器件接收多字节数据函数IRcvStr(u8 sla,u8 suba,u8 *s,u8 no)
//有形参sla:地址;suba:子地址;*s:数据数组;no:字节个数;有返回值1
//***************************************************************/
bit IRcvStr(u8 sla,u8 suba,u8 *s,u8 no)
{
        u8 i;
        
        Start_I2c();           //启动总线
        SendByte(sla);         //发送器件地址
        if(ack==0)
                return(0);
        SendByte(suba);        //发送器件子地址
        if(ack==0)
                return(0);        
        Start_I2c();
        SendByte(sla+1);
        if(ack==0)
                return(0);
        for(i=0;i<no-1;i++)
        {   
                *s=RcvByte();       //发送数据
                Ack_I2c(0);         //发送就答位
                s++;
        }
        *s=RcvByte();
        Ack_I2c(1);                             //发送非应位
        Stop_I2c();          //结束总线
        return(1);
}
/****************************************************************/
//延时函数delay(),有形参Count用于控制延时函数执行次数,无返回值
/****************************************************************/
void Delay_MS(u16 Count)
{
  u8 i,j;
  while (Count--)//Count形参控制延时次数
  {
    for(i=0;i<100;i++)
      for(j=0;j<40;j++);
  }
}
void _Nop()//1us
{
unsigned char i;
_nop_();
_nop_();
_nop_();
i=1;
while(--i);
}


回复

使用道具 举报

ID:958676 发表于 2021-8-3 18:28 | 显示全部楼层
STC89C52上可以,移植到STC12C5A60S2上就不行了,_Nop重新定义以上,机器周期,还是无效
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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