2020蓝桥杯单片机板各模块编写综合源码

该代码实现了一个用于蓝桥杯竞赛的单片机板上多个模块的功能,包括矩阵键盘、1302时钟芯片、18b20温度传感器、AD转换、串口通信、超声波测距等。通过矩阵键盘读取用户输入,根据输入执行相应操作,如显示温度、时间、读取光敏电阻值等,并具备串口数据收发功能。代码结构清晰,模块化设计便于理解和维护。
摘要由CSDN通过智能技术生成

2020蓝桥杯单片机板各模块编写综合源码


运用矩阵键盘,将蓝桥杯板子上的大部分模块分别实现,便于练习各个模块的使用。
附带2020官方资源包,在我的资源里可以下载查看。资源链接
***//主函数 ***

#include "common.h"
#include "ds1302.h"
#include "iic.h"
#include "onewire.h"
#include "stdio.h"

void init_all();
void delay(uchar t);

extern uchar seg_data[8];//将数码管赋值的数值扩展到main中,可以直接对特定的数码管赋值

uchar code led_show[24] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,
                           0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,
                           0x7e,0xbd,0xdb,0xe7,
                           0xe7,0xdb,0xbd,0x7e};


uchar flag_time = 0;
uchar get_key_value = 0;
uchar seg_count = 0;
uint flag_led = 0;
uchar led_count=0;
uchar key_pre=0;//不将按键归零

//接受温度
uchar wd; //整数
uint  wdf;//浮点数

//1302时钟芯片
extern char hour,minute,second;

//ad转换
uchar rd1;//光敏电阻 地址为0x01
uchar rd2;//可调电阻 地址为0x03

                           
//e2prom保存数据的地址,地址自选,或者题目要求具体地址
uchar code e2prom_addr[4] = {0x10,0x02,0x40,0x50};
//e2prom保存数据
uchar e2prom_data[4] = {1,2,3,4};
char i=0;

//接受串口数据
char get_uart_data;
//发送串口数据
char send_uart_data[20];

//超声波测距
uint ss=0;
uint s_count=0;//0.5s测一次

             
void main()
{
    init_all();
    while(1)
    {
        if(flag_time>=30)
        {
            flag_time = 0;
//          get_key_value = get_key();//独立按键
            get_key_value = get_key_16();//矩阵键盘
            if(get_key_value != 0)
                key_pre=get_key_value;
            switch(key_pre)
            {
                case 1:{ //读取温度整数                 
                    wd = read_wd();
                    get_seg(11,11,11,11,11,11,wd/10,wd%10);
                }break;
                case 2:{//读取温度带小数部分,数码管未添加小数点
                    wdf = read_wd_f();
                    get_seg(11,11,11,11,wdf/1000,wdf/100%10,wdf/10%10,wdf%10);
                }break;
                case 3:{//1302读取时间
                    read_time();
                    get_seg(hour>>4,hour&0x0f,10,minute>>4,minute&0x0f,10,second>>4,second&0x0f);

                }break;
                case 4:{//读取rd1光敏电阻
                    rd1 = read_atod(1);
                    get_seg(11,11,11,11,11,rd1/100,rd1/10%10,rd1%10);
                }break;
                case 5:{//读取rd2电阻
                    rd2 = read_atod(3);
                    get_seg(11,11,11,11,11,rd2/100,rd2/10%10,rd2%10);
                }break;
                case 6:{
                    if(get_key_value==6)//手动更新e2prom中的数据,避免不断刷新观察不清
                    {
                        //读取、写入e2prom数据        
                    e2prom_data[i] = read_data(e2prom_addr[i]);
                    delay(50);
                    write_data(e2prom_addr[i],e2prom_data[i]+1);
                    delay(50);
                    if(e2prom_data[i]<10)
                        get_seg(11,11,11,11,11,11,11,e2prom_data[i]);
                    else
                        get_seg(11,11,11,11,11,11,e2prom_data[i]/10,e2prom_data[i]%10);
                    i++;
                    if(i>=4){i=0;}
                    }
                }break;
                case 7:{//串口数据接收显示
                       get_seg(11,11,11,11,11,11,11,get_uart_data);
                }break;
                case 8:{//串口向上位机发送数据
                       if(get_key_value==8)
                           {
                            read_time();
                            //将时间存储到数组中要用int强转才有效加上字符'0'符合ASSIC码格式
                            send_uart_data[0]=(int)(hour>>4)+'0';
                            send_uart_data[1]=(int)(hour&0x0f)+'0';
                            send_uart_data[2]=':';   
                            send_uart_data[3]=(int)(minute>>4)+'0';
                            send_uart_data[4]=(int)(minute&0x0f)+'0';
                            send_uart_data[5]=':'; 
                            send_uart_data[6]=(int)(second>>4)+'0';
                            send_uart_data[7]=(int)(second&0x0f)+'0';
                            send_uart_data[8]='\0';//添加字符结束标志,不添加可能也没错

                           uart_sendstring(send_uart_data);
                            uart_sendstring("\r\n");//换行,缩进命令为:\r\t    
                           
                            } 

                }break;
                case 9:{
                    if(s_count>=400)
                    {
                        s_count=0;
                        
                        send_wave();
                        TR1=1;
                        while(P11==1&&TF1==0);
                        TR1=0;
                        if(TF1==1)
                        {
                            TF1=0;
                            ss=999;                        
                        }
                        else
                        {
                            
                            ss = TH1;
                            ss = ss<<8;
                            ss = ss | TL1;
                            ss = (uint)(ss * 0.017); TH1=0;TL0=0;
                            
                        }
                        get_seg(11,11,11,11,11,ss/100,ss/10%10,ss%10);
                    }
                    
                };break;
                case 10:seg_data[0]=1;seg_data[1]=0;break;
                case 11:seg_data[0]=1;seg_data[1]=1;break;
                case 12:seg_data[0]=1;seg_data[1]=2;break;
                case 13:seg_data[0]=1;seg_data[1]=3;break;
                case 14:seg_data[0]=1;seg_data[1]=4;break;
                case 15:seg_data[0]=1;seg_data[1]=5;break;
                case 16:seg_data[0]=1;seg_data[1]=6;break;
             }

        }
    }
}

void init_all()
{
//    char i;
    Y(4);P0=0xff;
    Y(5);P0=0x00;
    Y(0);
    
    init_timer();//初始化定时器
//    Timer1Init();//UartInit();
    write_time(0x10,0x46,0x55);//写入1302时间
    //uart_sendstring("hello world\0");
    read_wd();delay(50); //读取一次18b20的温度值防止后面读取温度不准确
    
//    for(i=0;i<4;i++)
//    {   //写入e2prom中的数据
//        write_data(e2prom_addr[i],e2prom_data[i]);
//        delay(50);//给个延时,给它时间让它写进去
//        delay(50);//给个延时,给它时间让它写进去
//    }
}

void timer0() interrupt 1
{
    flag_time++;
    flag_led++;

    if(key_pre==9)
        s_count++;
    
    if(flag_led>=500)
    {
        flag_led=0;
        Y(4);P0=led_show[led_count];Y(0);
        led_count++;
        if(led_count>=24)
            led_count=0;
    }
    
    show_seg(seg_count);
    seg_count++;
    if(seg_count>=8){seg_count=0;}    
    
}

void uart0() interrupt 4
{   
     if(RI==1)
     {
         RI=0;
         get_uart_data = SBUF;
         
     }
}

void delay(uchar t)
{
    uchar i,j;
    for(i=0;i<t;i++)
        for(j=0;j<110;j++);    
}

***//common模块 ***
common.h

#ifndef _COMMON_H_
#define _COMMON_H_

#include "STC15F2K60S2.H"


#define uchar unsigned char
#define uint  unsigned int

sbit TS = P1^0;
sbit RS = P1^1;

void Y(uchar channel);
void get_seg(uchar d1,d2,d3,d4,d5,d6,d7,d8);
void show_seg(uchar count);
void init_timer();
void Timer1Init(void);		//0微秒@12.000MHz
void send_wave();//超声波
void UartInit(void);
void uart_sendstring(char *str);

uchar get_key();
uchar get_key_16();


#endif

common.c

#include "common.h"
#include "intrins.h"

#define somenop _nop_()

//            ;_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_()

uchar code wela[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar code dula[12] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
uchar seg_data[8] = {11,11,11,11,11,11,11,11};

uchar flag_key_count = 0;
uchar key_value = 0;
bit   flag_key_down = 0;

void Y(uchar channel)
{
    switch(channel)
    {
        case 4: P2 = (P2 & 0x1f) | 0x80;break;
        case 5: P2 = (P2 & 0x1f) | 0xa0;break;
        case 6: P2 = (P2 & 0x1f) | 0xc0;break;
        case 7: P2 = (P2 & 0x1f) | 0xe0;break;
        case 0: P2 = (P2 & 0x1f) | 0x00;break;
    }
}
void get_seg(uchar d1,d2,d3,d4,d5,d6,d7,d8)
{
    if(d1<12) seg_data[0] = d1;
    if(d2<12) seg_data[1] = d2;
    if(d3<12) seg_data[2] = d3;
    if(d4<12) seg_data[3] = d4;
    if(d5<12) seg_data[4] = d5;
    if(d6<12) seg_data[5] = d6;
    if(d7<12) seg_data[6] = d7;
    if(d8<12) seg_data[7] = d8;
    
}
void show_seg(uchar count)
{
   Y(6);P0 = wela[count];
   Y(7);P0 = dula[seg_data[count]];
   Y(0);
}
void init_timer()
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x00;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 0;		//定时器1开始计时

    EA = 1;
    ET0 = 1;
	TR0 = 1;		//定时器0开始计时
    
}

void Timer1Init(void)		//0微秒@12.000MHz
{
//	AUXR &= 0xBF;		//定时器时钟12T模式
//	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x00;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 0;		//定时器1开始计时
}


void send_wave()
{
    char i=0;
    while(i<8)
    {   
        i++;
        P10=1;
        somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
        P10=0;
        somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;    
    }
}

void UartInit(void)		//2400bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0x1E;		//设定定时初值
	TH1 = 0xFB;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
    ES = 1;
}

//void uart_sendstring(char *str)
//{

//    char *s;
//    s = str;
//    ES = 0;
//    while(*s!='\0')
//    {
//        SBUF=*s;
//        while(TI==0);
//        TI s++;=0;
//       
//    }
//    ES = 1;
//}

uchar get_key()
{
    if((P3&0x0f)!=0x0f)
    {    flag_key_count++;}
    else
    {    flag_key_count=0;}

    if(flag_key_count>=5)
    {
        flag_key_count = 0;
        flag_key_down = 1;
        
        if(P33==0)
        {
            key_value=4;
        }
        else if(P32==0)
        {
            key_value=5;
        }
        else if(P31==0)
        {
            key_value=6;
        }
        else if(P30==0)
        {
            key_value=7;
        }
    }


    if(flag_key_down==1 && ((P3&0x0f)==0x0f))
    {
        flag_key_down=0;
        return key_value;
    }

    return 0;
}

uchar get_key_16()
{
   
    P3=0x0f;P44=0;P42=0;//p36、p37在矩阵键盘中用p42、p44替代
    if((P3&0x0f)!=0x0f)
    {
        flag_key_count++;
    }
    else
    {
        flag_key_count=0;
    }

    if(flag_key_count>=5)
    {
        
        flag_key_count=0;
        flag_key_down=1;

        P3=0x0f;P44=0;P42=0;//行扫描
        if(P30==0) {key_value=0;}
        else if(P31==0){key_value=4;}
        else if(P32==0){key_value=8;}
        else if(P33==0){key_value=12;}

        P3=0xf0;P44=1;P42=1;//列扫描
        if(P44==0){key_value=key_value+1;}
        else if(P42==0){key_value=key_value+2;}
        else if(P35==0){key_value=key_value+3;}
        else if(P34==0){key_value=key_value+4;}
        
    }
    
    //松开按键才赋值有效
    P3=0x0f;P44=0;P42=0;
    if(flag_key_down==1 && ((P3&0x0f)==0x0f))
    {
        flag_key_down=0;

        return key_value;
    }

    return 0;
   
}

char key()
{
    P3=0x0f;P44=0;P42=0;
    if((P3&0x0f)!=0x0f)
        flag_key_count++;
    else
        flag_key_count=0;
    
    if(flag_key_count>=5)
    {
        flag_key_count=0;
        flag_key_down=1;
        
        P3=0x0f;P44=0;P42=0;
        if(P30==0) key_value=0;
        else if(P31==0) key_value=4;
        else if(P32==0) key_value=8;
        else if(P33==0) key_value=12;
        
        P3=0xf0;P44=1;P42=1;
        if(P44==0) key_value = key_value+1;
        else if(P42==0) key_value = key_value+2;
        else if(P35==0) key_value = key_value+3;
        else if(P34==0) key_value = key_value+4;
    }
    
    P3=0x0f;P44=0;P42=0;
    if(flag_key_down==1 && ((P3&0x0f)==0x0f))
    {
        flag_key_down=0;
        return key_value;
    }
    return 0;
}

**//ds1302模块 **
ds1302.h

#ifndef __DS1302_H
#define __DS1302_H

//void Write_Ds1302(unsigned char temp);
//void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
//unsigned char Read_Ds1302_Byte( unsigned char address );

void read_time();
void write_time(char h,m,s);

#endif

ds1302.c

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include <reg52.h>
#include <intrins.h>

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位

char hour;
char minute;
char second;

void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}


void read_time()
{
   second = Read_Ds1302_Byte(0x81);
   minute = Read_Ds1302_Byte(0x83);
   hour   = Read_Ds1302_Byte(0x85);    
}
void write_time(char h,m,s)
{
    Write_Ds1302_Byte(0x80,s);
    Write_Ds1302_Byte(0x82,m);
    Write_Ds1302_Byte(0x84,h);    
}



***//onewire模块 ***
onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

//unsigned char rd_temperature(void);  //; ;
unsigned char read_wd();
unsigned int read_wd_f();

#endif

onewire.c

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "reg52.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
    t = t * 12;
	while(t--);
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

unsigned char read_wd()
{
    unsigned char low,high,temp;
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(1000);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    
    low = Read_DS18B20();
    high  = Read_DS18B20();
    
    high = high << 4;
    temp = high | (low>>4);
    
    return temp;
}


unsigned int read_wd_f()
{
    unsigned int low,high;
    unsigned int temp;
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(1000);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    
    low = Read_DS18B20();
    high  = Read_DS18B20();
    
    
    high = (high&0x0f) << 8;
    temp  = high | low;
    temp = (temp * 0.0625)*100;
    return temp;
    
}

//iic模块

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}



void write_data(unsigned char addr,unsigned char dat)
{
    IIC_Start();
    IIC_SendByte(0xa0);
    IIC_WaitAck();
    IIC_SendByte(addr);
    IIC_WaitAck();
    IIC_SendByte(dat);
    IIC_WaitAck();
    IIC_Stop();   
    
}
unsigned char read_data(unsigned char addr)
{
    unsigned char temp;    
    
    IIC_Start();
    IIC_SendByte(0xa0);
    IIC_WaitAck();
    IIC_SendByte(addr);
    IIC_WaitAck();
    IIC_Stop(); 
    
    IIC_Start();
    IIC_SendByte(0xa1);
    IIC_WaitAck();
    temp = IIC_RecByte();
    IIC_SendAck(0);
    IIC_Stop();

    return temp;
    
}
unsigned char read_atod(unsigned char addr)
{
    unsigned char temp;    
    
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(addr);
    IIC_WaitAck();
    IIC_Stop(); 
    
    IIC_Start();
    IIC_SendByte(0x91);
    IIC_WaitAck();
    temp = IIC_RecByte();
    IIC_SendAck(0);
    IIC_Stop();

    return temp;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值