历史上的今天
返回首页

历史上的今天

今天是:2025年01月22日(星期三)

正在发生

2021年01月22日 | MSP430G2553软件实现IIC

2021-01-22 来源:eefocus

程序框图

单片机IIC控制流程框图

代码实现

IIC实现代码(前面的宏定义适用于MSP430)

#define uchar unsigned char

#define uint unsigned int

//=====================================延时函数=================================

#define  CPU_F ((double)8000000)

#define  delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))

#define  delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))

//=====================================IIC地址设置=================================

#define  WHO_AM_I         0x75           //IIC地址寄存器(默认数值0x68,只读)--(6050)

#define  SlaveAddress     0x80           //IIC写入时的地址字节数据,+1为读取--(PCA9685)

//=====================================IIC端口定义=================================

#define  SCL1  P1OUT|=BIT4

#define  SCL0  P1OUT&= ~BIT4


#define  SDA1  P1OUT|=BIT5               //IIC数据引脚

#define  SDA0  P1OUT&= ~BIT5

#define  SDAIN  P1DIR&= ~BIT5

#define  SDAOUT  P1DIR|=BIT5

#define  SDADATA  (P1IN&BIT5)

//================================I2C起始信号================================

void I2C_Start()

{

    SDA1;               //拉高数据线

    SCL1;               //拉高时钟线

    delay_us(5);         //延时

    SDA0;               //产生下降沿

    delay_us(5);

    SCL0;               //拉低时钟线

}

//================================I2C停止信号================================

void I2C_Stop()

{

    SDA0;               //拉高数据线

    SCL1;

    delay_us(5);

    SDA1;               //产生上升沿

    delay_us(5);

}

//================================I2C发送应答信号 入口参数:ack (0:ACK 1:NAK)================================

void I2C_SendACK(uchar ack)

{

    SDAOUT;

    if(ack)

        SDA1;

    else

        SDA0;

    //SDA=ack;          //读应答信号

    SCL1;

    delay_us(5);

    SCL0;               //拉低时钟线

    delay_us(5);

}

//================================I2C接收应答信号================================

uchar I2C_RecvACK()

{

    uchar cy;

    SCL1;

    SDAIN;

    delay_us(5);

    if(SDADATA)

    {

        cy=1;

    }

    else

    {

        cy=0;

    }

    //cy=SDA;           //读应答信号

    SCL0;

    delay_us(5);

    SDAOUT;

    return cy;

}

//================================向I2C总线发送一个字节数据================================

void I2C_SendByte(uchar dat)

{

    uchar i;

    for(i=0;i<8;i++)    //8位计数器

    {

        if((dat<        {

            SDA1;

        }

        else

        {

            SDA0;

        }

        //SDA=cy;       //送数据口

        SCL1;

        delay_us(5);

        SCL0;

        delay_us(5);

    }

    I2C_RecvACK();

}

//================================从I2C总线接收一个字节数据================================

uchar I2C_RecvByte()

{

    uchar i;

    uchar dat=0,cy;

    SDA1;               //使能内部上拉,准备读取数据,

    SDAIN;              //8位计数器

    for(i=0;i<8;i++)

    {

        dat<<=1;

        SCL1;

        delay_us(5);

        if(SDADATA)

        {

            cy=1;

        }

        else

        {

            cy=0;

        }

        dat|=cy;        //读数据

        SCL0;

        delay_us(5);

    }

    SDAOUT;

    return dat;

}

//=======================向I2C设备写入一个字节数据======================================

void Single_WriteI2C(uchar REG_Address,uchar REG_data)

{

    I2C_Start();                        //起始信号

    I2C_SendByte(SlaveAddress);         //发送设备地址+写信号

    I2C_SendByte(REG_Address);          //内部寄存器地址

    I2C_SendByte(REG_data);             //内部寄存器数据

    I2C_Stop();                         //发送停止信号

}

//======================从I2C设备读取一个字节数据=====================================

uchar Single_ReadI2C(uchar REG_Address)

{

    uchar REG_data;


    I2C_Start();                        //起始信号

    I2C_SendByte(SlaveAddress);         //发送设备地址+写信号

    I2C_SendByte(REG_Address);          //发送存储单元地址,从0开始

    I2C_Start();                        //起始信号

    I2C_SendByte(SlaveAddress+1);       //发送设备地址+读信号

    REG_data=I2C_RecvByte();            //读出寄存器数据

    I2C_SendACK(1);                     //接收应答信号

    I2C_Stop();                         //停止信号


    return REG_data;

}

//======================================合成数据======================================

int GetData(uchar REG_Address)

{

    char H,L;

    H=Single_ReadI2C(REG_Address);

    L=Single_ReadI2C(REG_Address+1);

    return (H<<8)+L;                    //合成数据

}


单片机调用程序(对应于pca9685驱动板从机)

设置PWM频率


void setPWMFreq(float freq)

{

                uint prescale,oldmode,newmode;

                float prescaleval;

                freq_re=freq;

                freq *= 0.96;               // 用于纠正频率偏差

                prescaleval = 25000000;

                prescaleval /= 4096;

                prescaleval /= freq;

                prescaleval -= 1;

//                prescale = floor(prescaleval + 0.5);

                prescale=(int)(prescaleval + 0.5 );

                oldmode = Single_ReadI2C(PCA9685_MODE1);

                newmode = (oldmode&0x7F) | 0x10; // sleep

                Single_WriteI2C(PCA9685_MODE1, newmode); //调用之前写的IIC写入函数,go to sleep

                Single_WriteI2C(PCA9685_PRESCALE, prescale); // set the prescaler

                Single_WriteI2C(PCA9685_MODE1, oldmode);

                delay_ms(2);

                Single_WriteI2C(PCA9685_MODE1, oldmode | 0xa1);

}


设置pca9685各个舵机输出寄存器的值


// =========================输出通道设置,占空比设置从0到ON跳成高  再到off跳成低====================================

void setPWM(uint num, uint on, uint off)    //0--4096

{

                Single_WriteI2C(LED0_ON_L+4*num,on);

                Single_WriteI2C(LED0_ON_H+4*num,on>>8);

                Single_WriteI2C(LED0_OFF_L+4*num,off);

                Single_WriteI2C(LED0_OFF_H+4*num,off>>8);

}

// =========================num通道,ms高电平毫秒====================================

void setPWM_ms(uint num,float time_ms)

{

               uint time;

               time=(uint)((time_ms*freq_re/1000)*4096);

               setPWM(num, 0, time) ;

}

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

 * 名       称:setARC()

 * 功       能:设置舵机角度

 * 入口参数:舵机口num,角度arc

 * 出口参数:无

 * 说       明:

 * 范       例:无

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

void setARC(uint num,float arc)

{

float time_ms=arc*2/180+0.5;

setPWM_ms(num,time_ms);


}


推荐阅读

史海拾趣

明波通信(BWAVE)公司的发展小趣事

随着无线通信技术的快速发展,明波通信紧跟时代步伐,不断投入研发力量,在无线/移动通信领域取得了重大技术突破。公司成功开发出了一系列大规模集成电路(IP/ASIC)及相关控制软件,不仅提高了通信效率和质量,也赢得了国内外客户的广泛认可。这一时期的明波通信,已经成为国内通信行业的佼佼者。

旌芯半导体(GN)公司的发展小趣事

在2002年,一群从海外归来的留学生和技术专家,怀揣着对通信技术的热情与梦想,在上海创立了明波通信技术股份有限公司。他们深知国内在通信领域的技术与海外相比还有较大差距,因此决心将自己在海外学到的先进知识和经验,应用到国内的市场和技术创新中。明波通信从创立之初就致力于数字电视芯片的研究与开发,并逐渐在行业中崭露头角。

CONEC公司的发展小趣事

在电子行业中,技术的突破和创新是企业持续发展的关键。CONEC深知这一点,因此不断投入研发资源,力求在技术上取得突破。通过多年的努力,公司在某些关键技术领域取得了重要进展,如高速数据传输、低损耗材料应用等。这些技术突破不仅提升了公司的产品性能和质量,也使其在行业中保持了领先地位。

Elpaq公司的发展小趣事
Ceratech Corporation公司的发展小趣事

在电子行业的早期,Ceratech Corporation公司以其对滤波器技术的深入研究和不断创新而崭露头角。公司研发团队不断攻克技术难题,成功研发出一系列高性能的Ceratech滤波器,这些滤波器以其优异的性能和稳定性,迅速在市场中占据了一席之地。随着技术的不断积累和创新,Ceratech Corporation逐渐在滤波器领域树立起了自己的品牌和技术优势。

Festo公司的发展小趣事

作为一家以创新驱动的公司,Festo始终将创新作为公司发展的核心动力。近年来,Festo在研发领域的投资不断增加,推出了一系列具有颠覆性的新产品和解决方案。同时,Festo还积极响应全球可持续发展的趋势,致力于减少碳排放和提高能源效率。通过引入先进的能效措施和扩大光伏(PV)的使用,Festo成功实现了碳中和的目标,为电子行业的可持续发展做出了积极的贡献。

问答坊 | AI 解惑

大功率LED封装的要点

replyreload += \',\' + 380115;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

contact ID 协议 (安定宝协议)

我们公司现在做一个报警控制器,需要支持Contact Id 协议,但自己以前没有做过,而且那个协议文档写的不是很清楚,希望以前做过的能指点一下,或者也可以和我们公司合作(你以前做过硬件电路和软件实现)。 QQ:275556641 Email: yuangangaaa@163 ...…

查看全部问答>

PC Linux系统使用GPRS模块需要GPRS的驱动吗

各位大侠,小弟不才,问个简单问题:利用GPRS模块在Linux系统拨号上网只需要接口(比如串口)的驱动,而不需要GPRS本身的驱动吗?还是Linux系统自带这个驱动。…

查看全部问答>

AD采样问题-交流采样

我写了个用ad采样程序,用于采样交流电压,我发现每次程序运行后的第一个采样数据是错误的。例如: samples矩阵用于存放采样的结果值 samples[0]=390.3 samples[1]=40.5 samples[2]=63.4 samples[3]=78.8 。。。。 第一个采样点samples[0]是 ...…

查看全部问答>

wince6.0 支持TransparentBlt吗?

wince6.0 支持TransparentBlt吗?我在调试的时候该函数返回一直是0,不知道是为什么?各位大虾指导下!…

查看全部问答>

怎样破解iarewarm5.30?

我下的iar ewarm5.30照别个说的方法怎么补能破解呢? 未命名.JPG (53.53 KB) 下载次数:7 2010-6-15 20:52 …

查看全部问答>

帮忙看看2407的程序吧

帮忙看看2407点灯的程序吧,为什么lacc    #8语句中输入>8的数时,在单步调试运行时,延时程序就跳不出来了,好像死机了似的。可是lacc    #8语句中输入<=8的数就什么问题都没有。快帮忙看看吧,我都在这个问题上停留好长 ...…

查看全部问答>

谈喇叭阻抗问题。

  大家都知道喇叭最常见的是8欧阻抗,用万用表量,通常在8欧左右,小功率的就不说了。如上图这个8欧30W喇叭,满载电压约为15.5V 1.9365A,自损损耗就是30W,这样一算我就怀疑了,它上面标的8欧30W,30W是输出功率还是自身损耗呢???(喇 ...…

查看全部问答>

选择深度睡眠还是深度掉电?

对于LPC1114,想让它平时不工作,当按键按下时打醒它,进而用它控制电路其它部分上电,不知道平时让它在深度睡眠模式还是深度掉电模式啊?…

查看全部问答>

出售C8051F040+JTAG仿真器

由于毕业了,手头上的一些东西闲置没用。F040买了就没有用过,当然仿真器也是。现在都降价了!价格面议。有意者加我QQ:1003829876…

查看全部问答>