文章目录
- 1、基本简介
- 2、通信方式
- 3、参考STC12例程
- 参考文献
1、基本简介
2、通信方式
通过芯片手册我们可以了解到这个模块的输出有PWM和SMBus方式,PWM长期做嵌入式开发的已经很熟悉了,那么什么是SMBus呢?
SMBus(系统管理总线),最早由Intel提出,应用于移动PC和桌面PC系统中的低速率通信,是一种两线的接口。通过它,各设备之间以及系统的其他部分可以之间可以相互通信,它是基于IIC原理,接口和数据格式类似与IIC,同样有两个接口(1个时钟、一个数据),7位数据。可以说SMBus是IIC的一个子集。
3、参考STC12例程
#include <STC12C5A60S2.H>
#include <intrins.h>
#include <stdio.h>
/*=================================================
* 时钟宏定义
*=================================================*/
#define MAIN_Fosc 11059200L //宏定义主时钟HZ
//#define MAIN_Fosc 12000000L
/*=================================================
* 自定义数据类型
*=================================================*/
typedef unsigned char uchar;
typedef unsigned int uint;
//LCD1602硬件接口
#define LCD1602_DB P0 //LCD1602数据总线
sbit LCD1602_RS = P3^5; //RS端
sbit LCD1602_RW = P3^6; //RW端
sbit LCD1602_EN = P3^4; //EN端
//I2C模拟硬件接口定义
sbit SCL = P0^6;
sbit SDA = P0^7;
/*I2C常用变量宏定义*/
#define I2cRead 1 //I2C读方向位
#define I2cWrite 0 //I2C写方向
/*全局变量定义*/
uchar DataH,DataL,Pecreg;
/*============================自主适应时钟延时函数===========================================*/
//基于STC12单片机1us延时函数
//函数说明:内部调用
static void Delaym1us()
{
# if MAIN_Fosc == 11059200L
//晶振11.0592MHz
_nop_();
#elif MAIN_Fosc == 12000000L
//晶振12.000000MHZ
_nop_();
_nop_();
#endif
}
//基于STC12单片机us延时函数
//函数说明:外部调用
void Delay_us(uint time)
{
int i;
for(i=0; i<time; i++)
{
Delaym1us();
}
}
//基于STC12单片机ms延时函数
//函数说明:外部调用
void Delay_ms(uint time)
{
int i;
for(i=0; i<time; i++)
{
Delay_us(1000);
}
}
/*============================IIC===========================================*/
//I2C延时5us函数
void I2cDelay_5us(void)
{
Delay_us(5);
}
//I2C总线起始信号
void I2cStart(void)
{
SCL = 1;
SDA = 1;
I2cDelay_5us();//状态保持5us
SDA = 0;
I2cDelay_5us();//状态保持5us
}
//I2C总线停止信号
void I2cStop(void)
{
SCL = 0;
SDA = 0;
SCL = 1;
I2cDelay_5us();//状态保持5us
SDA = 1;
I2cDelay_5us();//状态保持5us
}
/********************************
*函数名称:ReadACK(void)
*函数输入:无
*函数返回:1非应答,0应答
*函数说明:I2C总线读从机应答信号
********************************/
bit ReadACK(void)
{
uint i;
SCL = 0;//拉低时钟总线,允许从机控制SDA
SCL = 1;//拉高,读SDA
I2cDelay_5us();
while((SDA==1) && (i<250))//等待SDA应答,或者超过时间默认应答
i++;
SCL = 0;
I2cDelay_5us();
return(0);//返回0应答
}
/***************************************
*函数名称:SendACK(bit i)
*函数输入:1主机发送非应答,0发送应答
*函数返回:无
*函数说明:主机发送应答信号
***************************************/
void SendACK(bit i)
{
SCL = 0; //拉低时钟总线,允许主机控制SDA
if(i) //发送非应答
SDA = 1;
else
SDA = 0;
SCL = 1; //拉高总线,让从机读SDA
I2cDelay_5us();
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1; //释放数据总线
}
/***************************************
*函数名称:I2cSendByte(uchar DAT)
*函数输入:DAT需要发送的数据
*函数返回:无
*函数说明:I2C发送一个字节数据
***************************************/
void I2cSendByte(uchar DAT)
{
uchar i;
for(i=0; i<8; i++) //分别写8次,每次写1位
{
SCL = 0; //拉低时钟总线,允许SDA变化
_nop_();
if(DAT & 0x80) //先写数据最高位
{
SDA = 1; //写1
_nop_();
}
else
{
SDA = 0; //写0
_nop_();
}
SCL = 1; //拉高时钟,让从机读SDA
_nop_();
DAT <<= 1; //为发送下一位左移1位
}
SCL = 0; //拉低时钟总线,允许SDA释放
_nop_();
SDA = 1; //释放数据总线
_nop_();
}
/*====================================
函数 :I2cReadByte()
参数 :无
返回值 :返回读出的一字节数据
描述 :I2C总线读一字节数据
====================================*/
uchar I2cReadByte(void)
{
uchar i, DAT;
SCL = 0;
_nop_();
SDA = 1;
_nop_();
for(i=0; i<8; i++)//分别读8次,每次读一位
{
DAT <<= 1; //数据左移1位,准备接收一位
SCL = 0; //拉低时钟总线,允许从机控制SDA变化
_nop_();
SCL = 1; //拉高时钟总线,读取SDA上的数据
_nop_();
if(SDA)
DAT |= 0X01;//为1则写1,否则不行执行写1,通过左移补0
_nop_();
}
return(DAT); //返回读出的数据
}
//读取温度数据
uint temperatureRead(void)
{
I2cStart();
I2cSendByte(0xB4);//Send SlaveAddress(写从设备地址)
ReadACK();
I2cSendByte(0x07);//Send Command(写命令)
ReadACK();
I2cStart();
I2cSendByte(0x01);
DataL = I2cReadByte();
SendACK(0);
DataH = I2cReadByte();
SendACK(0);
Pecreg = I2cReadByte();
I2cStop();
return(DataH*256+DataL);
}
//读取到最终温度
//程序涉及到温度计算,详细参考芯片手册
float SMBus_ReadTemp(void)
{
float temp;
temp = temperatureRead();
temp = temp * 0.02 - 273.15;
return temp;
}
/*============================LCD1206===========================================*/
/*=================================================
*函数名称:Read_Busy
*函数功能:判断1602液晶忙,并等待
=================================================*/
void Read_Busy()
{
uchar busy;
LCD1602_DB = 0xff;//复位数据总线
LCD1602_RS = 0; //拉低RS+
LCD1602_RW = 1; //拉高RW读
do
{
LCD1602_EN = 1;//使能EN
busy = LCD1602_DB;//读回数据
LCD1602_EN = 0; //拉低使能以便于下一次产生上升沿
}while(busy & 0x80); //判断状态字BIT7位是否为1,为1则表示忙,程序等待
}
/*=================================================
*函数名称:LCD1602_Write_Cmd
*函数功能:写LCD1602命令
*调用:Read_Busy();
*输入:cmd:要写的命令
=================================================*/
void LCD1602_Write_Cmd(uchar cmd)
{
Read_Busy(); //判断忙,忙则等待
LCD1602_RS = 0;
LCD1602_RW = 0; //拉低RS、RW操作时序情况1602课件下中文使用说明基本操作时序章节
LCD1602_DB = cmd;//写入命令
LCD1602_EN = 1; //拉高使能端 数据被传输到LCD1602内
LCD1602_EN = 0; //拉低使能以便于下一次产生上升沿
}
/*=================================================
*函数名称:LCD1602_Write_Dat
*函数功能:写LCD1602数据
*调用:Read_Busy();
*输入:dat:需要写入的数据
=================================================*/
void LCD1602_Write_Dat(uchar dat)
{
Read_Busy();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_EN = 1;
LCD1602_EN = 0;
}
/*=================================================
*函数名称:LCD1602_Dis_Str
*函数功能:在指定位置显示字符串
*调用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();
*输入:x:要显示的横坐标取值0-40,y:要显示的行坐标取值0-1(0为第一行,1为第二行)
*str:需要显示的字符串
=================================================*/
void LCD1602_Dis_Str(uchar x, uchar y, uchar *str)
{
if(y) x |= 0x40;
x |= 0x80;
LCD1602_Write_Cmd(x);
while(*str != '\0')
{
LCD1602_Write_Dat(*str++);
}
}
/*=================================================
*函数名称:Init_LCD1602
*函数功能:1602初始化
*调用: LCD1602_Write_Cmd();
=================================================*/
void Init_LCD1602()
{
LCD1602_Write_Cmd(0x38); // 设置16*2显示,5*7点阵,8位数据接口
LCD1602_Write_Cmd(0x0c); //开显示
LCD1602_Write_Cmd(0x06); //读写一字节后地址指针加1
LCD1602_Write_Cmd(0x01); //清除显示
}
void main()
{
float Temperature = 0; //温度数据变量(浮点型)
char TempValue[10] = {0}; //温度值(字符串)
uchar TestStr[] = {"Temp:"};
Init_LCD1602(); //1602初始化
LCD1602_Dis_Str(0, 0, &TestStr[0]); //显示字符串
while(1)
{
Temperature = SMBus_ReadTemp();
Delay_ms(100);
sprintf(TempValue, "%.1f", Temperature);//浮点型转换字符串
LCD1602_Dis_Str(6, 0, &TempValue[0]);
}
}
参考文献
[1] MLX90614中文资料