电子闹钟(atmega16)

电子闹钟

功能要求:

1、  实时时钟(由数码管显示时:分,中间的“:”一亮一灭表示1秒,可用小数点表示,也可以用一个LED表示);

2、  时钟的时、分可调节;

3、  闹钟时间可以设置,闹钟初值为8:00,(并保存在EEPROM中,掉电不丢失);

4、  闹钟时间到,蜂鸣器响10秒;

5、  按键使用数量不宜超过5个;

6、  整点时间,通过串行口上传一次时钟信息;

7、  自行补充新功能(选做项);

单片机型号:atmega16

流程图

proteus模拟电路图:

 代码(适用于atmega16实物,如需用以上电路图模拟还需修改IO口配置)

#include <iom16v.h>
#include <macros.h>

unsigned char led_buf[] = { 0x3F, 0x06, 0x5B, 0x4F,0x66, 0x6D, 0x7D, 0x07,0x7F, 0x6F };  //共阴极数码管编码表,分别表示0~f;
unsigned char position[6] = { 0xfe, 0xfd, 0xef, 0xdf, 0xbf, 0x7f }; // 位选码
unsigned char show[] = "NOW IS : ";
unsigned char transmit_time[10] = "0123456789";
unsigned char maohao = ':', temp[6];
unsigned char time[3], time_set[3], YuSheTime[3] = { 0, 0, 8 }; //时、分、秒计数和设置单元及定时时间8:00,确保掉电不清除
unsigned char dis_buf[10]; //显示缓冲区,存放要显示的10个字符的段码值
unsigned char  timecounterofkeys, timecounter;
unsigned char clock_state = 2, set_state, return_time;
int time_add, point, set_on, time_1second, key_stime_ok;

#define key_input PINB //按键输入口
#define key_mask 0B00001111 //按键输入屏蔽码
#define key_no 0
#define key_s1 1 //s1按键
#define key_s2 2 //s2按键
#define key_s3 3 //s3按键
#define key_s4 4 //s4按键
#define key_state_0 0 //按键状态0 1 2
#define key_state_1 1 
#define key_state_2 2

void io_init(void);//I/O口初始化函数//
void T0_init(void);//T/C0初始化函数///
void usart_init(unsigned int baud);//usart初始化//
void usart_transmit_byte(unsigned char data);//发送一个字符//
void usart_transmit_string(unsigned char* buf);//发送一个字符串//
unsigned char usart_recieve_byte(void);//接收一个字符//
void time_to_disbuffer(unsigned char* time);//时钟时间送显示缓冲区函数//
void display(void);//时钟时间送显示缓冲区函数//
void timer0_comp_isr(void);//显示输出函数///
unsigned char read_key(void);//读取按键函数//
void time_dealer(void);//时间处理函数//
void zhengdianhanshu(void);//整点时间函数//
void main(void);//主函数

//I/O口初始化函数//
void io_init(void)
{
    DDRC = 0xFF; //LED段码输出

    DDRD = 0xfe;  //LED位控输出(1111 1110)
    PORTD = 0xFF; //输出高电平

    DDRB = 0xe0; //按钮输入口(1110 0000)
    PORTB = 0xFF;

    DDRA = 0xff;  //输出口
    PORTA = 0xff; //输出高电平
}

///T/C0初始化函数///
void T0_init(void)
{
    OCR0 = 0xF9;  //OCR0 = 0xF9(249),(249+1)/125=2ms
    TCCR0 = 0x0B; //内部时钟,CTC模式,64分频,8M/64=125KHz
}

usart初始化//
void usart_init(unsigned int baud)
{
    UBRRH = (unsigned char)(baud >> 8);
    UBRRL = (unsigned char)baud;         // 波特率:4800,时钟频率:8MHz (0110 0111)
    UCSRA = 0x20;
    UCSRB = (1 << TXEN) | (1 << RXEN);   //发送使能|接收时能(0001 1000)
    UCSRC = (1 << URSEL) | (3 << UCSZ0); //异步模式,帧格式:1个起始位,8个数据位,无校验,1个停止位;
}
发送一个字符//
void usart_transmit_byte(unsigned char data)
{

    while (!(UCSRA & (1 << UDRE)))
    {
        ;
    }
    UDR = data;
}
计时器Timer0:比较匹配中断服务,定时:2ms
#pragma interrupt_handler timer0_comp_isr: iv_TIMER0_COMP //计时器Timer0:比较匹配输出
void timer0_comp_isr(void)
{

    display();
    if (++timecounterofkeys >= 5)
    {
        timecounterofkeys = 0;
        key_stime_ok = 1;  //10ms时,给key_stime_ok赋值为1
        if (!(++timecounter % 25))
        {
            set_on = !set_on;
        }
        if (timecounter >= 100) //判断是否达到一秒
        {
            timecounter = 0;
            time_1second = 1;
        }
    }
}
发送一个字符串//
void usart_transmit_string(unsigned char* databuf)
{
    while (*databuf != '\0')
    {
        usart_transmit_byte(*databuf++);
    }
}

接收一个字符//
unsigned char usart_recieve_byte(void)
{
    // 等待接收数据
    while (!(UCSRA & (1 << RXC)))
        ;
    // 从缓冲器中获取并返回数据
    return UDR;
}

时钟时间送显示缓冲区函数//
void time_to_disbuffer(unsigned char* time)
{
    unsigned char i, j = 0;
    for (i = 0; i <= 2; i++)
    {
        dis_buf[j++] = time[i] % 10;
        dis_buf[j++] = time[i] / 10;
    }
}

///显示输出函数///
void display(void)
{

    static unsigned char posit = 2; //从分钟开始显示

    PORTD = 0xFF; //!输出高电平

    PORTC = led_buf[dis_buf[posit]]; //缓存段码

    if (set_on && (posit == clock_state)) //被调位闪烁
    {
        PORTC = 0x00;
    }

    if (point && posit == 4) //控制第四位小数点闪烁
    {
        PORTC |= 0x80;
    }

    PORTD = position[posit]; //控制输出的位

    if (++posit >= 6)
    {
        posit = 2;          //从分钟开始显示
    }
}

读取按键函数//
unsigned char read_key(void)
{

    static unsigned char key_state = 0, key_press;

    unsigned char key_return = key_no; //相当于key_return =0;

    key_press = key_input & key_mask; //读取按键I/O电平

    switch (key_state)
    {
    case key_state_0: //按键初始态

        if (key_press != key_mask)
        {
            key_state = key_state_1;
        }
        break; //键被按下,状态转换到键确认态

    case key_state_1: //按键确认态

        if (key_press == (key_input & key_mask))

        {

            if (key_press == 0b00001110)
            {
                key_return = key_s1;
            }

            else if (key_press == 0b00001101)
            {
                key_return = key_s2;
            }

            else if (key_press == 0b00001011)
            {
                key_return = key_s3;
            }
            else if (key_press == 0b00000111)
            {
                key_return = key_s4;
            }

            key_state = key_state_2; // 状态转换到键释放态
        }
        else
        {
            key_state = key_state_0; // 按键已抬起,转换到按键初始态
        }
        break;
    case key_state_2:
        if (key_press == key_mask)
        {
            key_state = key_state_0;
        }
        break; //按键已释放,转换到按键初始态
    }
    return key_return;
}
//时间处理函数//
void time_dealer(void)
{
    while (1)
    {
        if (++time[0] >= 60)      // 秒加1
        {
            time[0] = 0;          //秒超过60,秒数清0
            if (++time[1] >= 60)
            {
                time[1] = 0;         //分数超过60,分清0
                if (++time[2] >= 24)
                {
                    time[2] = 0;     //时超过24,时清0
                }
            }
        }
    }
} 

//整点时间函数//
void zhengdianhanshu(void)//整点时间,通过串行口上传一次时钟信息/
{
       
            if ((time[1] == 0) && (time[0] == 0)) //分秒同时为零,表示整点,向串口上传一次时间
            {
                temp[5] = time[2] % 10;
                temp[4] = (unsigned char)time[2] / 10;
                temp[3] = time[1] % 10;
                temp[2] = (unsigned char)time[1] / 10;
                temp[1] = time[0] % 10;
                temp[0] = (unsigned char)time[0] / 10;
                usart_transmit_string(show);
                usart_transmit_byte(transmit_time[temp[4]]);
                usart_transmit_byte(transmit_time[temp[5]]);
                usart_transmit_byte(maohao);
                usart_transmit_byte(transmit_time[temp[2]]);
                usart_transmit_byte(transmit_time[temp[3]]);
                usart_transmit_byte(maohao);
                usart_transmit_byte(transmit_time[temp[0]]);
                usart_transmit_byte(transmit_time[temp[1]]);
                usart_transmit_string("\r\n");
            }
}
主函数//
void main(void)
{
    unsigned char key_temp, i;
    //初始化
    T0_init(); //T/C0初始化
    io_init(); //I/O口初始化
    usart_init(103); //usart初始化,波特率设置为4800;
    //设时间初值07:59:00
    time[2] = 7;
    time[1] = 59;
    time[0] = 0;

    TIMSK = 0x12; //允许T/C1比较匹配A中断,允许T/C0比较匹配中断,开放全局中断
    SEI();

    while (1)
    {
        if (time_1second) //1秒到
        {
            time_1second = 0;
            point = ~point; //闪烁标志,一秒亮,一秒灭
       //     time_dealer();
            if (++time[0] >= 60) //! 秒加1,
            {
                time[0] = 0;         //!秒数超过60,秒数清0
                if (++time[1] >= 60) //!分加1
                {
                    time[1] = 0;         //!分数超过60,分数清0
                    if (++time[2] >= 24) //!时加1
                    {
                        time[2] = 0; //!时数超过24,时数清0
                    }
                }
            }
            //最初十秒不操作就进入初始设置时间
            if ((++return_time >= 10) && (clock_state != 6))
            {
                clock_state = 6;
            }
            if (clock_state == 6)
            {
                time_to_disbuffer(time);
            }
            zhengdianhanshu();
            /*整点时间,通过串行口上传一次时钟信息*/
/*            if ((time[1] == 0) && (time[0] == 0)) //!分钟,秒钟为零,表示整点,就上传一次时间
            {
                temp[5] = time[2] % 10;
                temp[4] = (unsigned char)time[2] / 10;
                temp[3] = time[1] % 10;
                temp[2] = (unsigned char)time[1] / 10;
                temp[1] = time[0] % 10;
                temp[0] = (unsigned char)time[0] / 10;
                usart_transmit_string(show);
                usart_transmit_byte(transmit_time[temp[4]]);
                usart_transmit_byte(transmit_time[temp[5]]);
                usart_transmit_byte(maohao);
                usart_transmit_byte(transmit_time[temp[2]]);
                usart_transmit_byte(transmit_time[temp[3]]);
                usart_transmit_byte(maohao);
                usart_transmit_byte(transmit_time[temp[0]]);
                usart_transmit_byte(transmit_time[temp[1]]);
                usart_transmit_string("\r\n");
            }
*/
            /*设定闹钟时间到,蜂鸣器响10秒*/
            if ((time[2] == YuSheTime[2]) && (time[1] == YuSheTime[1]) && (time[0] == YuSheTime[0]))
            {
                PORTA = 0x7f; //(0111 1111),低电平蜂鸣器响
            }
            if ((time[2] == YuSheTime[2]) && (time[1] == YuSheTime[1]) && (time[0] == YuSheTime[0] + 10))
            {
                PORTA = 0xff; //(1111 1111),高电平蜂鸣器关
            }
        }
        if (key_stime_ok) //10ms到,键处理
        {
            key_stime_ok = 0;
            key_temp = read_key(); //调用按键接口程序

            if (key_temp) //确认有按键按下
            {
                return_time = 0;        //置零时间,直至等待十秒不操作
                if (key_temp == key_s1) // s1键按下,设定时钟时间功能
                {

                    if (++clock_state >= 7)
                    {
                        clock_state = 2;
                    }
                    if (clock_state == 2)
                    {
                        for (i = 0; i <= 2; i++)
                        {
                            time_set[i] = 0;
                        }
                        time_to_disbuffer(time_set);
                    }
                    if (clock_state == 6)
                    {
                        for (i = 0; i <= 2; i++)
                        {
                            time[i] = time_set[i];
                        }

                        time_to_disbuffer(time);
                    }
                }

                if (key_temp == key_s2)   //s2键按下,设定闹钟时间功能
                {

                    if (++clock_state >= 7)
                    {
                        clock_state = 2;
                    }
                    if (clock_state == 2)   //不按按钮,设定闹钟初始值为08:00
                    {
                        time_to_disbuffer(YuSheTime);
                    }
                    if (clock_state == 6)
                    {

                        for (i = 0; i <= 2; i++)
                        {
                            YuSheTime[i] = time_set[i];
                        }
                        time_to_disbuffer(YuSheTime);
                    }
                }

                if ((clock_state != 6) && (key_temp == key_s3))  //每按一下s3,被调试位数值加一
                {
                    if (clock_state % 2)
                    {
                        time_set[clock_state / 2] += 10;
                    }
                    else
                    {
                        if ((time_set[clock_state / 2] % 10) == 9)
                        {
                            time_set[clock_state / 2] -= 9;
                        }
                        else
                        {
                            time_set[clock_state / 2] += 1;
                        }
                    }
                   
                    if (time_set[0] >= 60)
                    {
                        time_set[0] -= 60;
                    }

                    if (time_set[1] >= 60)
                    {
                        time_set[1] -= 60;
                    }

                    if (time_set[2] >= 24)
                    {
                        time_set[2] -= 10;
                    }
                    time_to_disbuffer(time_set);  //设置时间送入显示缓存
                }

                

                if (key_temp == key_s4)   //s4按下,向串口传输当前时间
                {
                    temp[5] = time[2] % 10;
                    temp[4] = (unsigned char)time[2] / 10;
                    temp[3] = time[1] % 10;
                    temp[2] = (unsigned char)time[1] / 10;
                    temp[1] = time[0] % 10;
                    temp[0] = (unsigned char)time[0] / 10;
                    usart_transmit_string(show);
                    usart_transmit_byte(transmit_time[temp[4]]);
                    usart_transmit_byte(transmit_time[temp[5]]);
                    usart_transmit_byte(maohao);
                    usart_transmit_byte(transmit_time[temp[2]]);
                    usart_transmit_byte(transmit_time[temp[3]]);
                    usart_transmit_byte(maohao);
                    usart_transmit_byte(transmit_time[temp[0]]);
                    usart_transmit_byte(transmit_time[temp[1]]);
                    usart_transmit_string("\r\n");
                }
            }
        }
    }
}

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值