蓝桥杯单片机第十届省赛题程序实现

文章目录

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
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值