参考学习视频,用比赛给的驱动写的,重新定义了数据的长度,解决水量和计费溢出问题。在用PCF8951(8位AD转换,2^8 即0-255)进行AD转换时,将数据0-255转换0-100
255*0.39=99.45 近似为100 存在转换误差无法绝对精确蓝桥杯CT107D单片机参考电压为5V,所以(1.25V/5V) *100=25。或者直接计算,(1.25/5)*255=63.75 近似为64
对驱动进行的修改
1 在官方驱动加了一个读取数据的函数
2 将官方驱动的somenop扩大8倍,因为官网驱动提供的驱动代码测试环境:12T, 8051, 12MHz
IAP15F2K61S2具有内部振荡器,振荡器频率可在ISP软件中调整使用或调试驱动代码时,选手需根据设定的片内振荡器频率、所使用单片机的机器周期对代码进行调整;
利用官方驱动写的读取函数
uchar IIC_read(uchar add)
{
uchar temp;
IIC_Start();
IIC_SendByte(0x90);//PCF8951地址
IIC_WaitAck();
IIC_SendByte(add);//采集AD信息的地址
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);//进行读操作
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
temp=0.39*temp; //0.39*255=99.45 约等于100将数据0-255转换0-100
return temp;
}
主函数
#include <STC15F2K60S2.h>
#include "iic.h"
sbit s7=P3^0;
sbit s6=P3^1;
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//1 2 3 4 5 6 7 8 9 - 灭
uchar code dottab[]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};
//带小数点的数字,此程序主要用第二位,第六位 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
uchar yi,er,san,si,wu,liu,qi,ba;
uchar tt=0;//定时器计数
uint ml_10=0;//10毫升
uint money=0;////计费 全部初始化为0,避免内存分配出问题
void Delay1ms(uchar ms);
void display1(uchar yi,uchar er);
void display2(uchar san,uchar si);
void display3(uchar wu,uchar liu);
void display4(uchar qi,uchar ba);
void allinit();
void keyscan();
void Timer0Init(void);
void adrun();
void main()
{
allinit();
Timer0Init();
yi=11,er=0,san=5,si=0,wu=0,liu=0,qi=0,ba=0;
while(1)
{
display1( yi, er);
display2( san, si);
display3( wu, liu);
display4( qi, ba);
adrun();
keyscan();
}
}
void Delay1ms(uchar ms) //@12.000MHz
{
unsigned char i, j;
uchar k;
for(k=ms;k>0;k--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
void display1(uchar yi,uchar er)
{
P2=0XC0;
P0=0X01;
P2=0XE0;
P0=tab[yi];
Delay1ms(1);
P2=0XC0;
P0=0X02;
P2=0XE0;
P0=dottab[er];
Delay1ms(1);
}
void display2(uchar san,uchar si)
{
P2=0XC0;
P0=0X04;
P2=0XE0;
P0=tab[san];
Delay1ms(1);
P2=0XC0;
P0=0X08;
P2=0XE0;
P0=tab[si];
Delay1ms(1);
}
void display3(uchar wu,uchar liu)
{
P2=0XC0;
P0=0X10;
P2=0XE0;
P0=tab[wu];
Delay1ms(1);
P2=0XC0;
P0=0X20;
P2=0XE0;
P0=dottab[liu];
Delay1ms(1);
}
void display4(uchar qi,uchar ba)
{
P2=0XC0;
P0=0X40;
P2=0XE0;
P0=tab[qi];
Delay1ms(1);
P2=0XC0;
P0=0X80;
P2=0XE0;
P0=tab[ba];
Delay1ms(1);
}
void allinit()
{
P2=0X80;
P0=0XFF;//关LED
P2=0XC0;
P0=0XFF;
P2=0XE0;
P0=0XFF;//关数码管
P2=0XA0;
P0=0X00;//关蜂鸣器 继电器
}
void keyscan()
{
if(s7==0)
{
Delay1ms(5);
if(s7==0)
{
P2=0XA0;
P0=0X10;
//开始计费
wu=0,liu=0,qi=0,ba=0;
EA=1;ET0=1;
}
while(!s7);
}
else if(s6==0)
{
Delay1ms(5);
if(s6==0)
{
EA=0;ET0=0; //停止计费
P2=0XA0;
P0=0X00;
money=ml_10*5;// 49995
wu=money/10000;
liu=money%10000/1000;
qi=money%1000/100;
ba=money%100/10; //显示费用
ml_10=0;
}
while(!s6);
}
}
void Timer0Init(void) //5毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xA0; //设置定时初值
TH0 = 0x15; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void timer0() interrupt 1
{
tt++;
if(tt==20)
{
tt=0;
ml_10=ml_10+1;//ml_10代表10ml 此时最多计算到9999 防止溢出
wu=ml_10/1000;
liu=ml_10%1000/100;
qi=ml_10%100/10;
ba=ml_10%10;
}
if(ml_10>9999)
{
EA=0;ET0=0;
P2=0XA0;
P0=0X00;//断开继电器 L10
money=ml_10*5;// 49 995
wu=money/10000;
liu=money%10000/1000;
qi=money%1000/100;
ba=money%100/10; //显示费用
ml_10=0;
}
}
void adrun()//读取AD转换结果并判断
{
uchar num;
num=IIC_read(0x01);//采集光敏电阻数据
if(num<25)// 1.25/5 *100=25 小于1.25V L1亮
{
P2=0X80;
P0=0XFE;
}
else //大于1.25V L1亮
{
P2=0X80;
P0=0XFF;
}
}
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(12MHz)
日 期: 2011-8-9
*/
#include "iic.h"
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
////应答位控制
//void IIC_Ack(unsigned char ackbit)//没有用到,注释处理,避免警告
//{
// if(ackbit)
// {
// SDA = 0;
// }
// else
// {
// SDA = 1;
// }
// somenop;
// SCL = 1;
// somenop;
// SCL = 0;
// SDA = 1;
// somenop;
//}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
uchar IIC_read(uchar add)
{
uchar temp;
IIC_Start();
IIC_SendByte(0x90);//PCF8951地址
IIC_WaitAck();
IIC_SendByte(add);//采集AD信息的地址
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);//进行读操作
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
temp=0.39*temp; //0.39*255=99.45 约等于100将数据0-255转换0-100
return temp;
}
#ifndef _IIC_H
#define _IIC_H
#include <STC15F2K60S2.h>
#include "intrins.h"
/*将原来的somenop扩大8倍,因为官网驱动提供的驱动代码测试环境:12T, 8051, 12MHz
IAP15F2K61S2具有内部振荡器,振荡器频率可在ISP软件中调整
使用或调试驱动代码时,选手需根据设定的片内振荡器频率、所使用单片机的机器周期对代码进行调整;*/
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
#define uchar unsigned char
#define uint unsigned int
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//函数声明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(unsigned char ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
uchar IIC_read(uchar add);
#endif