main.c
#include<reg52.h>
#include<intrins.h>
#include<iic.h>
sbit hc138_A=P2^5;
sbit hc138_B=P2^6;
sbit hc138_C=P2^7;
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
#define uchar unsigned char
#define uint unsigned int
unsigned char key_value = 0;
unsigned char shuzi[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //0-9
unsigned char shuzi1[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//0-9//含小数点
uint hz = 0; //NE555产生的信号的频率
uchar flag_S4 = 0; //S4按键功能,=0为电压显示界面=1为频率显示界面
uchar flag_S5 = 0; //S5按键功能,=0为固定2V输出,=1则跟随输入
uchar flag_S6 = 0; //S6按键功能,=0为启用LED,=1则禁用
uchar flag_S7 = 0; //S7按键功能,=0为启用数码管=1则禁用
uint V_RB2_read = 0; //从RB2电位器读到的数据 0-255
uint V_RB2_real = 0; //RB2的实际电压值的100倍//方便显示
/*****配置138译码器*****/
void HC138(unsigned int n)
{
switch(n)
{
case 4:
hc138_A=0 ; hc138_B=0 ; hc138_C=1; break;
case 5:
hc138_A=1 ; hc138_B=0 ; hc138_C=1; break;
case 6:
hc138_A=0 ; hc138_B=1 ; hc138_C=1; break;
case 7:
hc138_A=1 ; hc138_B=1 ; hc138_C=1; break;
}
}
/*****延时函数*****/
void delay(unsigned int k)
{
while(k--);
}
/*****数码管显示函数*****/
void Display()
{
char x = 0x01;
int i = 0;
for(i = 1;i<=8 ;i++)
{
HC138(6);
P0 = x;
x = _crol_(x,1);
HC138(7);
P0 = 0xff;delay(50); //数码管消隐放到这个地方好一点
if(flag_S7 == 0)
{
if(flag_S4 == 0)
{
switch (i)
{
case 1 :P0 = 0xc1; break;
case 2 :P0 = 0xff; break;
case 3 :P0 = 0xff; break;
case 4 :P0 = 0xff; break;
case 5 :P0 = 0xff; break;
case 6 :P0 = shuzi1[V_RB2_real/100]; break;
case 7 :P0 = shuzi[V_RB2_real%100/10]; break;
case 8 :P0 = shuzi[V_RB2_real%10]; break;
}
}
else if(flag_S4 == 1)
{
switch (i)
{
case 1 :P0 = 0X8E; break;
case 2 :P0 = 0xff; break;
case 3 :P0 = 0xff; break;
case 4 :P0 = 0xff; break;
case 5 :P0 = 0xff; break;
case 6 :P0 = shuzi[hz/100]; break;
case 7 :P0 = shuzi[hz%100/10]; break;
case 8 :P0 = shuzi[hz%10]; break;
}
}
}
else if(flag_S7 == 1)
P0 = 0xff;
delay(500);P0 = 0xff;
}
}
/*****按键扫描函数*****/
void key_scan()
{
if((S4 == 0) || (S5 == 0) || (S6 == 0) || (S7 == 0)) //其中一个按键被按下则为1
{
delay(100); //延时消抖
if(S4 == 0) key_value = 4;
if(S5 == 0) key_value = 5;
if(S6 == 0) key_value = 6;
if(S7 == 0) key_value = 7;
while((S4 == 0) || (S5 == 0) || (S6 == 0) || (S7 == 0))//等待按键松开
{
Display();
}
}
}
/*****定时器TIM0和TIM1初始化*****/
void TIM_Init()
{
TMOD = 0x16;
TH0 = 0XFF;
TL0 = 0XFF; //定时器0用作计数,16位计数器模式
TH1 = (65535 - 10000)/256; //设置定时器1初值,高八位放在TH1中,定时时间10000us = 10ms
TL1 = (65535 - 10000)%256; //设置定时器1初值,低八位放在TL1中
TR0 = 1; //启动T0
TR1 = 1; //启动T1
ET0 = 1; //开T0中断
ET1 = 1; //开T1中断
EA = 1; //开总中断
}
unsigned int count = 0; //脉冲计数,计数器TIM0产生一次中断则+1
/*****定时器0中断服务函数*****/
void TIM0_work() interrupt 1
{
count = count + 1;
}
/*****定时器1中断服务函数*****/
unsigned int time = 0; //设置计时标志,定时器TIM1每产生一次中断则+1
void TIM1_work() interrupt 3 //定时器1的中断号为3
{
TH1 = (65535 - 10000)/256; //设置定时器1初值,高八位放在TH1中,
TL1 = (65535 - 10000)%256; //设置定时器1初值,低八位放在TL1中,
time++;
if(time == 100) //1s
{
time = 0; //清零
hz = count; //1s钟产生的次数即频率
count = 0; //清零,重新计数
}
}
void key_real()
{
if(key_value == 4)
{
if(flag_S4 == 0)
flag_S4 = 1;
else if(flag_S4 == 1)
flag_S4 = 0;
}
else if(key_value == 5)
{
if(flag_S5 == 0)
flag_S5 = 1;
else if(flag_S5 == 1)
flag_S5 = 0;
}
else if(key_value == 6)
{
if(flag_S6 == 0)
flag_S6 = 1;
else if(flag_S6 == 1)
flag_S6 = 0;
}
else if(key_value == 7)
{
if(flag_S7 == 0)
flag_S7 = 1;
else if(flag_S7 == 1)
flag_S7 = 0;
}
key_value = 0;
}
void LED_work()
{
HC138(4);
if(flag_S4 == 0)
{
L1 = 0; L2 = 1;
}
else if(flag_S4 == 1)
{
L1 = 1; L2 = 0;
}
if((V_RB2_real < 150) || (V_RB2_real >= 250 && V_RB2_real<350 ))
L3 = 1;
else if((V_RB2_real>=150 && V_RB2_real<250) || V_RB2_real>=350)
L3 = 0;
if(hz<1000 || (hz>=5000 && hz<10000))
L4 = 1;
else if((hz>=1000 && hz<5000) || hz>=10000)
L4 = 0;
if(flag_S5 == 0)
L5 = 0;
else if(flag_S5 == 1)
L5 = 1;
}
void main()
{
HC138(5);
P0 = 0X00;
HC138(4);
P0 = 0XFF;
TIM_Init();
while(1)
{
init_pcf8591();
V_RB2_read = adc_pcf8591();
V_RB2_real = V_RB2_read * 1.961;
key_scan();
key_real();
if(flag_S5 == 0)
dac_pcf8591(102);
else if(flag_S5 == 1)
dac_pcf8591(V_RB2_read);
if(flag_S6 == 0)
LED_work();
else if(flag_S6 == 1)
{
HC138(4);
P0 = 0xff;
}
Display();
}
}
iic.c
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
该程序为蓝桥杯单片机比赛官方所提供的参考代码
*/
#include "reg52.h"
#include "intrins.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//总线启动条件
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(bit 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;
}
//向PCF8591发送信号,准备读取0x03的数据
void init_pcf8591(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0X43); //PCF8591的通道三,接滑动变阻器Rb2,若是光敏电阻则为0x01
IIC_WaitAck();
IIC_Stop();
}
//读取数据
unsigned char adc_pcf8591(void)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
return temp;
}
/* 在D/A引脚输出0-5v电压*/
/* 参数dat范围0-255,对应电压0-5v */
void dac_pcf8591(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
iic.h
#ifndef _IIC_H
#define _IIC_H
//函数声明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(bit ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
void init_pcf8591(void);
unsigned char adc_pcf8591(void);
void dac_pcf8591(unsigned char dat);
#endif