📄 main.c
字号:
/*-----------------------------------------------
名称:IIC协议 PCF8591ADDA转换 显示有4个,注意只有一个可以调节电压的
内容:此程序通过IIC协议对DAAD芯片操作,读取电位器的电压通过液晶显示,并输出模拟量,用LED亮度渐变指示
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h> //包含NOP空指令函数_nop_();
#define AddWr 0x90 //写数据地址(理解手册)
#define AddRd 0x91 //读数据地址
sbit Sda=P2^0; //定义总线连接端口
sbit Scl=P2^1;
sbit dula=P2^6;
sbit wela=P2^7;
bit ADFlag; //定义AD采样标志位
char code dm[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //7段数共阴码管段码表0~9
//char wm[]={0XFE,0XFD,0XFB,0XF7,0XEF,0XDF}; //从左到右6位数码管(P0^0为0时,左1选中)
/****************************数码管显示有关***********************************/
void delayuint(unsigned int i)
{
while(i--);
}
//把三位整数的每一位取出
char q,b,s,g;
void convert(int DATA)
{
q=DATA/1000;
b=DATA%1000/100;
s=DATA%100/10;
g=DATA%10;
}
int DATA0; //用来存放上次的DATA值
void show_led8(float t) //把t送到数码管上扫描一遍 (0<t<100的四位浮点数(带2位小数))
{
int DATA=t*100; //若t带了多位小数也只取2位,赋给int型小数放弃
if(DATA0!=DATA)
convert(DATA0=DATA);
//处理千位
if(q!=0)
{
wela=1;
P0=0xfe;
wela=0;
//送百位段码
dula=1;
P0=dm[q];
dula=0;
delayuint(250); //delay(100)是916us(12M)
}
//处理百位 (对应小数的个位,须点亮dp点)
//先关段码(送暗码),再开下一位
dula=1;
P0=0;
dula=0;
wela=1;
P0=0xfd;
wela=0;
dula=1;
P0=dm[b]|0x80; //包含小数点
dula=0;
delayuint(250);
//处理十位 (对应小数的十分位)
//先关段码(送暗码),再开下一位
dula=1;
P0=0;
dula=0;
wela=1;
P0=0xfb;
wela=0;
dula=1;
P0=dm[s];
dula=0;
delayuint(250);
//处理个位 (对应小数的百分位)
//先关段码(送暗码),再开下一位
dula=1;
P0=0;
dula=0;
wela=1;
P0=0xf7;
wela=0;
dula=1;
P0=dm[g];
dula=0;
delayuint(250);
/*退出前关闭所有数码管,是必须要的,否则会可能出现单个数码管持续亮*/
dula=1;
P0=0;
dula=0;
}
/****************************数码管显示有关(OVER)********************************************/
/*------------------------------------------------
初始化定时器1
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10; //T1方式1
TH1=0x0B; //Init value
TL1=0xDC;
//PT1=1; // 优先级
EA=1; /* interupt enable */
ET1=1; /* enable timer1 interrupt */
TR1=1;
}
/*------------------------------------------------
启动IIC总线
------------------------------------------------*/
void Start(void)
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Sda=0;
_nop_(); //成功启动
Scl=0; //允许SDA改变
}
/*------------------------------------------------
停止IIC总线
------------------------------------------------*/
void Stop(void)
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Sda=1;
_nop_(); //成功停止
Scl=0; //允许SAD改变以准备数据
}
/*------------------------------------------------
(主机)应答IIC总线
------------------------------------------------*/
void Ack(void) //时钟有效期间,SDA保持0
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
/*------------------------------------------------
(主机)非应答IIC总线
------------------------------------------------*/
void NoAck(void) //时钟有效期间,SDA保持1
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void Send(unsigned char Data)
{
unsigned char BitCounter=8;
unsigned char temp;
do
{
temp=Data;
Scl=0;
_nop_();
if((temp&0x80)==0x80)
Sda=1;
else
Sda=0;
Scl=1;
temp=Data<<1;
Data=temp;
BitCounter--;
}
while(BitCounter);
Scl=0;
}
/*------------------------------------------------
读入一个字节并返回
------------------------------------------------*/
unsigned char Read(void)
{
unsigned char temp=0;
unsigned char temp1=0;
unsigned char BitCounter=8;
Sda=1; //让出数据总线给8591
do
{
Scl=0; //允许8591改变(准备)SDA数据
_nop_(); //等待数据有效
Scl=1; //使数据有效(单片机可用)
_nop_();
if(Sda) //单片机读SDA并判断
temp=temp|0x01;
else
temp=temp&0xfe;
if(BitCounter-1!=0)
{
temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}
while(BitCounter);
return(temp);
}
/*------------------------------------------------
读取ch通道AD转换的值,有返回值
------------------------------------------------*/
unsigned char ReadADC(unsigned char Ch)
{
unsigned char Data;
Start(); //启动
Send(AddWr); //写入芯片地址——写数据地址0x90
Ack(); //应该是等8591应答吧?
//发送”控制字“
Send(0x40|Ch); //写入选择的通道,本程序只用单端输入,差分部分需要自行设置
//Chl的值分别为0、1、2、3,分别代表1-4通道
//0100 00xx
Ack();
Start();
Send(AddRd); //写入地址---读数据地址0x91
Ack();
Data=Read(); //读数据
Scl=0;
NoAck();
Stop();
return Data; //返回值
}
/*------------------------------------------------
主程序
------------------------------------------------*/
void main()
{
unsigned char ADtemp; //定义中间变量
float U=0; //电压值
//unsigned int TempData[6];
Init_Timer1();
while(1)
{
if(ADFlag) //定时采集输入模拟量
{
ADFlag=0;
ADtemp=ReadADC(0); //8位二进制温度值
U=ADtemp*5.0/255; //把采样的数字值再还原为模拟值
}
show_led8(U);
}
}
/*------------------------------------------------
定时器中断程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3 using 1//定时器1执行数码管动态扫描
{
static unsigned int j;
TL1=0xDC; //重新赋值 62500US=62.5MS中断一次
TH1=0x0B;
j++;
if(j==4) //62.5*4=250ms 一秒钟采样四次
{j=0;ADFlag=1;} //定时置位AD采样标志位
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -