51单片机学习--数字时钟数字电压表

一、学习要求 
1.功能 1:数字电压表(0808或stc A/D)。 
2.功能 2:数字时钟,显示时、分、秒,可通过按键设定时间。 
3.将功能 1、功能 2 合并。 
4.扩展功能。(发送“cx”字符串到单片机,单片机将会返回电压值和时间)

解:

proteus原理图及仿真、代码和使用方法等相关文件:https://download.csdn.net/download/chenger_32123/10577316

实现了LCD1602里光标的移动、闪烁的同时电压值可以同步显示。

基本功能:

51单片机学习--数字时钟数字电压表_第1张图片

 

串口:

 

 

 

/*********************main.c**********************/

 

/*********************main.c**********************/

/*******************************************
//2017/12/4 
//芯片:STC89C52 
//晶振:12MHz  12T模式:12个时钟周期做一个机器周期
//功能:lcd1602显示adc0808采集到的电压值,同时显示时钟,时钟可通过按键设置。
//串口波特率:[email protected]
*******************************************/
#include
#include"main.h"
#include"lcd1602.h"
#include"adc0808.h"
#include"read_key.h"
/**************************************
//主函数
***************************************/
void main()
{    
    uchar value[COUNT];
    uchar count=0;
    uint voltage;
    uchar display_flag=0;    //lcd1602显示标志
    initialize();    //初始化
    LCD_StringOut(0x80,"Time:");//lcd1602第一行显示
    LCD_StringOut(0x80+0x40,"Voltage:"); //lcd1602第二行显示
    while(1)
    {
        value[count]=digital_out();    //获取adc808数字输出量并保存在数组中
        count++;
        if(COUNT==count)   //若获取够了COUNT个数则求均值
        {    
            voltage=filter(value,count)*1.0/255*VOLTAGE_REFER;
            count=0;
        }

        if(key_flag)   //约每20mS扫描一次键盘
        {
            key_process(read_key()); //读键盘值并处理
            key_flag=0;
            display_flag++;

        }

        if(display_flag>=10)    //约每200mS更新一次LCD1602显示
        {
            lcd_display(voltage); //LCD1602显示电压值
            display_flag=0;         //显示标志变量清零
        }

        if(inquire_flag)       //发送时间到PC
        {    
            serial_send();
            inquire_flag=0;    //查询标志清零
        }
    }
}
/**************************************
//初始化函数
***************************************/
void initialize()
{
    key_set=1;    //定义连接按键的IO口为读取模式
    key_cursor=1;
    key_add=1;
    LCD_Initialize();    //lcd1602初始化
    adc0808_initialize();//ADC0808初始化
    serial_initialize(); //串口初始化
    ET0=1;      //开启定时器0中断
    ES=1;     //开串口中断
    EA=1;    //开总中断
    TR0=1;   //启动定时器0
}
/**************************************
//串口初始化函数
***************************************/
void serial_initialize()      //[email protected]
{
    PCON &= 0x7F;        //波特率不倍速
    SCON = 0x50;        //8位数据,可变波特率
//    AUXR &= 0xBF;        //定时器1时钟为Fosc/12,即12T
//    AUXR &= 0xFE;        //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;        //清除定时器1模式位
    TMOD |= 0x20;        //设定定时器1为8位自动重装方式
    TL1 = 0xF3;        //设定定时初值
    TH1 = 0xF3;        //设定定时器重装值
    ET1 = 0;        //禁止定时器1中断
    TR1 = 1;        //启动定时器1
}
/**************************************
//定时器0中断函数
***************************************/
void timer0_interrtupt() interrupt 1 
{
    static uchar i=0;
    i++;
    if(200==i)    //约每20mS进入一次
    {
        i=0;
        key_flag=1;      //扫描键盘标志变量
    }

    if(count_flag)     
    {
        counter++;
        if(10000==counter)
        {
            counter=0;
            second++;
            if(60==second)
            {
                second=0;
                minute++;
                if(60==minute)
                {
                    minute=0;
                    hour++;
                    if(24==hour)
                    {
                        hour=0;
                    }
                }
            }
        }
    }

    clock=!clock;    //ADC0808时钟
}
/**************************************
//串口中断函数
***************************************/
void serial_interrupt() interrupt 4
{
    static bit count=0;         //定义静态局部变量
    static uchar temp_str[3];
    if(RI)    //接收
    {                          
        RI=0;                  //接收中断标志位清零
        temp_str[count]=SBUF;
        if('c'==temp_str[count] && 0==count)
        {                        /*含有"cx"字符即为查询*/
            count=1;
        }
        else if(1==count && 'x'==temp_str[count])
        {
            count=0;
            inquire_flag=1;      //表示收到"cx"字符,标志位置1
        }
        else count=0;
    }

    if(TI)     //发送
    {
        TI=0;        //发送中断标志位清零
        send++;        //发送下一个字符
        if(*send != '\0')
        {
            SBUF=*send;    //未遇到"\0"结束字符,则继续发送
        }
    }
}
/**************************************
//lcd1602显示函数
***************************************/
void lcd_display(uint _voltage)
{
    display2[0]=_voltage/1000 + '0';
    display2[2]=_voltage%1000/100 + '0';
    display2[3]=_voltage%1000%100/10 + '0';
    display2[4]=_voltage%1000%100%10 + '0';
    LCD_StringOut(0x80+0x49,display2); //显示电压值

    if(cursor_blink)
    {
        display1[0]=hour/10 +'0';     //时十位
        display1[1]=hour%10 +'0';     //时个位
        display1[3]=minute/10+'0';    //分十位
        display1[4]=minute%10+'0';  //分个位
        display1[6]=second/10+'0';    //秒十位
        display1[7]=second%10+'0';    //秒个位
        LCD_StringOut(0x80+0x06,display1);    //lcd1602显示时间
    }
    else
    {
        switch(cursor)    //判断光标位置
        {
            case 0:
                display1[0]='_';
                display1[1]='_';
                break;
            case 1:
                display1[3]='_';
                break;
            case 2:
                display1[4]='_';
                break;
            case 3:
                display1[6]='_';
                break;
            case 4:
                display1[7]='_';
                break;
        }
        LCD_StringOut(0x80+0x06,display1);//光标闪烁
    }

    if(set_flag)
    {
        if(0 == cursor_blink)
        {
            cursor_blink=8; //约每1.6秒闪烁一次光标
        }
        else
        {
            cursor_blink--;
        }
        
    }
    else
    {
        cursor_blink=1;
    }
}
/**************************************
//滤波函数
//功能:接收一维数组,length是数组长度。中位值平均滤波法(防脉冲干扰平均滤波法),
//采样length个数据,去掉一个最大值和最小值,然后计算length-2个数据的算术平均值
//input:数组首地址,数组长度。
//output:去除最小值和最大值后的算术平均值
//注意:由于定义为无符号,所以只能计算非负数。且length>=3。
***************************************/
uchar filter(uchar *_value,uchar length)
{
    uchar temp;
    uchar i,j;
    uint sum=0;
    for(j=1;j *(_value+i+1))
            {
                temp=*(_value+i);
                *(_value+i)=*(_value+i+1);
                *(_value+i+1)=temp;
            }
        }
    }
    for(i=1;i

 

你可能感兴趣的:(51单片机学习--数字时钟数字电压表)