历史上的今天
今天是: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);
}
史海拾趣
|
我们公司现在做一个报警控制器,需要支持Contact Id 协议,但自己以前没有做过,而且那个协议文档写的不是很清楚,希望以前做过的能指点一下,或者也可以和我们公司合作(你以前做过硬件电路和软件实现)。 QQ:275556641 Email: yuangangaaa@163 ...… 查看全部问答> |
|
各位大侠,小弟不才,问个简单问题:利用GPRS模块在Linux系统拨号上网只需要接口(比如串口)的驱动,而不需要GPRS本身的驱动吗?还是Linux系统自带这个驱动。… 查看全部问答> |
|
我写了个用ad采样程序,用于采样交流电压,我发现每次程序运行后的第一个采样数据是错误的。例如: samples矩阵用于存放采样的结果值 samples[0]=390.3 samples[1]=40.5 samples[2]=63.4 samples[3]=78.8 。。。。 第一个采样点samples[0]是 ...… 查看全部问答> |
|
我下的iar ewarm5.30照别个说的方法怎么补能破解呢? 未命名.JPG (53.53 KB) 下载次数:7 2010-6-15 20:52 … 查看全部问答> |
|
帮忙看看2407点灯的程序吧,为什么lacc #8语句中输入>8的数时,在单步调试运行时,延时程序就跳不出来了,好像死机了似的。可是lacc #8语句中输入<=8的数就什么问题都没有。快帮忙看看吧,我都在这个问题上停留好长 ...… 查看全部问答> |




