基于AVR单片机的上下课自动打铃系统的实现

发布者:游走人间最新更新时间:2015-06-23 来源: 51hei关键字:AVR单片机  上下课  自动打铃系统 手机看文章 扫描二维码
随时随地手机看文章
昨晚花一晚上把这些资料整理了一下,全部发出来了。
由于补课没有铃。3月份做了这个东西,已实际使用,稳定运行一个学期。
上运行图:

 

硬件如下:AVR ATmega16单片机,开发板(用到上面的:继电器、LED走马灯、两个按钮)、门铃、LED若干、16Mhz无源晶振。
 
硬件照片:
开发板:
AVR单片机:
晶振:

 

——————————好了 照片晒完了,下面开始正文——————————
原理图如下:
好吧我的能耐真大,这电路图不是用什么CAD专业软件画的,而是用Windows画 图板用鼠标一笔一划画的。。。所以效果不是很好,凑合着看吧,知道个大概就行了。(开发板上肯定还有其他资源,电路图中的资源也不止开发板上的。这个电路 图是本系统的原理图而不是开发板的全部电路图,画的只是和本系统有关的东西,开发板上其他无关的就不画了,也不需要画)[page]
简单说明下:
L1~L8对应开发板上的8个LED;D2~D6对应上面运行图上的那5个红色“上课指示灯”;D1为一盏绿色的LED(运行图上注意点看,用透明胶包住的那个绿色LED),用于监视程序是否在运行(晶振是否起振,是否死机);K1 K2用于选择上午下午(上午有早读,下午没有)。继电器不用说了,控制门铃开关用。
下面放出源程序。(刚刚我已在程序中加入了很多注释了,后面还是要做下解析):
————源程序(本程序版权归李彦锋所有)————
#define  uchar unsigned char
#define  uint  unsigned int
#define  ulong unsigned long int
volatile uint nowtime;//计时变量。然后下面的几个变量是一些逻辑控制的
volatile uint ledmode;
volatile uint shangkeledmode;
volatile uint shangkeledtime;
volatile uint class;//上下课逻辑,上课为1,下课为0,见主函数

#include
#include

void port_init(void)
{
DDRB=0xFF;
PORTB=0x00;
DDRC=0xFF;
DDRA=0XFF;
DDRD|=0XF0;
//初始化IO口
}


void timer0_init(void)
{

TCCR0 = 0x00;
TCNT0 = 0x06;
OCR0  = 0xFA; 
TCCR0 = 0x03;
//初始化timer0
}
//timer0本系统中用于控制上下课指示灯闪烁
#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
tm0rsf();//别看漏
TCNT0 = 0x06; 
}

//TIMER1 initialize - prescale:256
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:  1.000Sec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x0B; //setup
TCNT1L = 0xDC;
OCR1AH = 0xF4;
OCR1AL = 0x24;
OCR1BH = 0xF4;
OCR1BL = 0x24;
ICR1H  = 0xF4;
ICR1L  = 0x24;
TCCR1A = 0x00;
TCCR1B = 0x04; //start Timer
//初始化timer1
}

//timer1本系统中用于上课时间和下课时间计时

#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
tm1rsf();//哈哈可能有人漏看了这里,回调函数执行另一个函数,这样程序看起来更整洁,这是我的编程习惯^v^

TCNT1H = 0x0B; 
TCNT1L = 0xDC; //重载高低值

//timer1回调函数
}


void init_devices(void)
{
CLI(); 
port_init();
timer0_init();
timer1_init();
MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x05; 
SEI(); 
}


void delay(uint ms) //这个就不用说了 死循环延迟
{
    uint i,j;
    for(i=0;i             {
                    for (j=0;j<2300;j++);
                }
}

void tm0rsf()//控制上课指示灯闪烁的函数,不喜欢写在回调函数里,这样程序看起来更工整。。。
{

if(class==1)//是否上下课,上课就闪,下课就不闪。
{
shangkeledtime++;
    if (shangkeledtime==150)//150ms闪一下。其他自己看吧。。。。
    {
        shangkeledtime=0;
            if(shangkeledmode==1) //开灯,相应IO输出高电平
            {
                PORTA|=0X54;
                    PORTC|=0x02;
                        PORTD|=0x20;
                    shangkeledmode=0;
            }
            else //关灯,相应IO输出低电平(接地)
            {
                PORTA&=0X03;
                    PORTC&=0xFC;
                        PORTD&=0XDF;
                shangkeledmode=1;//逻辑自己看吧。。。。
            }
    }
}
else
{
    PORTA&=0X03;
        PORTC&=0xFC;
        PORTD&=0XDF;
}
}

void tm1rsf()//timer1回调函数执行的函数
{
nowtime++;//计时变量自增
if(ledmode==1)//嗯这个就是控制D0 LED闪烁的了,主要就是看timer1是不是在走。
{
    ledmode=0;
        PORTA|=0x01;
}
else
{
    ledmode=1;
        PORTA&=0XFE;
}

}

void ring()//响铃函数,控制继电器的。。(PC7输出高电平)
{
PORTC=0xFF;//因为PC口只有用到一个PC7所以不管这么多懒得算了直接全部输出高电位
delay(300);
PORTC=0x00;
delay(8300);
PORTC=0xFF;
delay(300);
PORTC=0x00;
delay(8300);
}
uchar key_press()//检测K1K2是否按下。。
{
    uchar j;
    DDRD|=0X0F;
        PORTD|=0X0F;
        
        DDRD&=0XF0;
        
        j=PIND;
        j=j&0X0F;
        if(j==0X0F)
        {
          return 0;
        }
        else
        {
         return 1;
        }
        
}

uchar key_scan()//检测是K1还是K2按下。。
{
    uchar key;
    delay(10);
        if(key_press())
        {
        key=PIND;
        key&=0X0F;
        switch(key)
        {
           case 0X0E: 
               key=1;
                   break;
           case 0X0D:
               key=2;
                   break;
           default:        
               key=0;                
        }
          while(key_press());
        }
        else
        {
          key=16;
        }
        return key;
}

void main()//好了主函数开始了。。。
{
    uchar i,j;
        uint k,mode;
        uint ledmode;
init_devices();//初始化IO。。上面有。

k=0;
ledmode=1;//逻辑自己看,不用解释。。。

        while(k==0) //注意了 这一段是上电后等待按下K1K2的。
        {
          if(ledmode==1)//上电后LED走马灯在那狂闪(按下之前)
          {
              PORTB=0XF0;delay(80);
                  ledmode=0;
          }
          else{PORTB=0X0F;delay(80);ledmode=1;}
          i=key_press();
          if(i)
          {//判断按的哪个
             j=key_scan();
                 if (j==1)
                 {mode=1;k=1;}
                 if (j==2)
                 {mode=2;k=1;}
          }
        }
        
        
if (mode==1)//如果按的K1,也就是早上用,有早读的
{
        uint overzaodu;
        uint canoverzaodu;
        overzaodu=0;
        canoverzaodu=0;
    PORTB=0XF3;//早读上课时跑马LED亮上面2盏(亮上面。。代表上午^v^)
        nowtime=0;
        class=1;
while(canoverzaodu==0)
{
        if (class==1)
    {
                    if (nowtime==1200)//先上20分钟的早读
                        {
                                class=0;
                                nowtime=0;
                                overzaodu++;
                                ring();//早读下课打铃
                        }
    }
        else
        {

                    if (nowtime==300)//早读休息5分钟,接下来自己看吧
                        {
                            
                                
                                class=1;
                                nowtime=0;
                                overzaodu++;
                            ring();
                                ring();
                                PORTC=0xFF;
                                delay(300);
                                PORTC=0x00;
                        }
        }
        if (overzaodu==1)
        
        {
            PORTB=0XF1;//早读下课,LED多亮一盏
        }
        if (overzaodu==2)
        {
        canoverzaodu=1;
        PORTB=0XF0;//早读结束,LED亮完上面4盏。。
        }//然后跳出早读while,进入到下面正常上课while--上课40分钟,下课10分钟,上课,下课…………无限循环。。。
}
}

if (mode==2)//按下K2,也就是下午用的
{
    PORTB=0X0F;
        class=1;//逻辑,上课为1下课为0
                            ring();
                                ring();
                                PORTC=0xFF;
                                delay(300);
                                PORTC=0x00;//这都是打铃用的。。上课比较吵,要打5遍。(一个ring打两遍,两个ring后直接在这里控制IO再打一遍)
}

nowtime=0;

while(1)//正常上课while,这里就不解释太多了,逻辑和上面早读的差不多的

{


     if (class==1)
    {
                    if (nowtime==2400)//是否够40分钟
                        {
                                class=0;
                                nowtime=0;//计时变量清零
                                ring();//打铃,下课打2遍就好了(一个ring两遍,具体看上面ring函数)
                        }
    }
        else
        {
                    if (nowtime==600)
                        {
                            
                                
                                class=1;
                                nowtime=0;
                            ring();
                                ring();
                                PORTC=0xFF;
                                delay(300);
                                PORTC=0x00;//上课打5遍铃,其他就不解释这么多了,逻辑一样的自己看就行。
                        }
        }
}
}
————源程序(本程序版权归李彦锋所有)————
再简单说下吧,程序中的逻辑就不说了。
1.点亮L1~L8为PB0~PB7输出低电平(接地),因为那头接的是VCC +5V的正电压。
2.PC7输出高电位,继电器B和C导通,接通门铃,就响了。
3.D1~D6我是直接把LED的正负接在IO口上的,所以输出电位的时候一高一低。其实可以IO口上全接正然后统一接地,但是这样麻烦,反正有足够的IO口,就这么干了。
附:最早是用内部时钟,然后后来跑不准,折腾了我一个星期,后来才发现是内部时钟的问题,上了个晶振,解决问题。。。
好了就说到这里,结束。
关键字:AVR单片机  上下课  自动打铃系统 引用地址:基于AVR单片机的上下课自动打铃系统的实现

上一篇:AVR中断运用报警2路指示
下一篇:AVR 1-99秒1602启停显示

推荐阅读最新更新时间:2024-03-16 14:04

AVR单片机改造遥控车
利用玩具遥控车的高频发射电路和高频接收电路,结合单片机 进行数据传输,模拟两通道比例控制遥控器。 发射端用ATTINY24从TX的8号脚控制玩具遥控器的高频发射部分 接收端用ATTINY24从RX2的3号脚接收信号。然后PWM控制 遥控车的两个电机,一个由电位器反馈。另一个由测速 盘反馈。 数据结构 0 高电平100us,低电平300us 1 高电平200us,低电平200us 数据帧结构 16位为一个包起始2位(10),地址2位,数据10位,结束2位(01) 每5个包为一个循环 1号包 全0包,不含起始结束,用于接收端复位。 2,3号包 地址01号数据。 4,5号包 地址02号数据。 纠错采用重复校验,当收到两组数据
[单片机]
<font color='red'>AVR单片机</font>改造遥控车
avr单片机和stm32区别与优缺点分析
  摘要:avr单片机和stm32单片机是目前使用较广泛的单片机,那么avr单片机和stm32单片机有什么区别呢?有什么优劣势呢?   一、AVR单片机介绍   AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced InstrucTIon Set CPU) 精简指令集高速8位单片机。可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。   avr单片机特点:   1. avr系列没有类似累加器A的结构,它主要是通过R16~R31寄存器来实现A的功能。在avr中,没有像51系列的数据指针DPTR,而是由X(由 R26、R27组成)、Y(由R28、R29组成)、
[单片机]
AVR单片机uPD6121/AS6122等红外编码芯片的解码程序
#include #define uchar unsigned char #define ulong unsigned long /*------------------------------显示-----------------------------------*/ #define LED _DATA PORTB const uchar tab ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; /* 0 1 2 3 4 5 6 7 8 9 A B C
[单片机]
AVR单片机端口操作
说明:本节重点介绍真正双向端口操作的方法,及与伪双向端口操作的不同。跑马灯例子。建议先看跑马灯,再绕回来看前面的介绍。 AVR端口是真正的双向端口,不像51伪双向。这也是AVR的一项优势,只是操作时大家注意DDRn就可以了。真正双向端口在模拟时序方面不如伪双向的方便。 DDRn PORTn PINn 解释:n为端口号:ABCDE DDRn:控制端口是输入还是输出,0为输入,1为输出。个人记忆方法:一比零大所以往外挤,即1为输出,0为输入。 PORTn:从引脚输出信号,当DDRn为1时,可以通过PORTn=x等端口操作语句给引脚输出赋值。 PINn:从引脚读输入信号,无论DDRn为何值,都可以通过x=PINn获得端口n
[单片机]
数字温度传感器TC77与AVR单片机的接口设计
  AVR系列的单片机内部集成了TWI(Two-wire SerialInterface)总线。该总线具有I2C总线的特点,即接线简单,外部硬件只需两个上拉电阻,使用时钟线SCL和数据线SDA就可以将128个不同的设备互连到一起;而且支持主机和从机操作,器件可以工作于发送器模式或接收器模式,数据传输率高达400 kHz。正因为TWI总线具有这么多的优点,因此受到了使用者的青睐。   由于该总线与传统的I2C总线极其相似。因此不少人误以为TWI总线就是I2C总线,其实这只是一种简单化的理解。TWI总线是对I2C总线的继承和发展。它定义了自已的功能模块和寄存器,寄存器各位功能的定义与I2C总线并不相同;而且TWI总线引入了状奁寄
[单片机]
数字温度传感器TC77与<font color='red'>AVR单片机</font>的接口设计
AVR单片机AD转换的电源滤波电路
为减小AD转换的电源干扰,Mega16芯片有独立的AD电源供电。官方文档推荐在VCC串上一只10uH的电感(L1),然后接一只0.1uF的电容到地(C3)。 Mega16内带2.56V标准参考电压。也可以从外面输入参考电压,比如在外面使用TL431基准电压源。不过一般的应用使用内部自带的参考电压已经足够。习惯上在AREF脚接一只0.1uF的电容到地(C4)。 重要说明:实际应用时,如果你想简化线路,可以将AVCC直接接到VCC,AREF悬空。即这部分不需要任何的外围零件。
[单片机]
<font color='red'>AVR单片机</font>AD转换的电源滤波电路
avr单片机驱动12864液晶程序
/*LCD12864显示子程序*、 #include util/delay.h #define uchar unsigned char #define uint unsigned int #define SETLCD12864RS PORTA|=(1 PA4) #define SETLCD12864RW PORTA|=(1 PA5) #define SETLCD12864EN PORTA|=(1 PA6) #define CLLCD12864RS PORTA&=~(1 PA4) #define CLLCD12864RW PORTA&=~(1 PA5) #define CLTLCD12864EN PORTA&=~(1 PA6) #d
[单片机]
基于AVR单片机的核磁共振仪床体检测系统
  1 引言   近年来随着医学技术的快速发展,核磁共振仪已经在大中型医院中被广泛的应用。目前,在核磁共振仪的生产过程中,床体部分要与磁体一起搬入电磁屏蔽室组装后才能进行检测,这对人员和物资都是很大的浪费。针对这种状况,本文设计出了一套核磁共振仪床体部分的运动控制与检测系统,它能够对床体部分独立进行检测,而不必将全部系统在屏蔽室安装后检测,从而降低了核磁共振仪床体部分的生产和检测成本,缩短了生产周期。   本设计以通用医疗集团的Ovation5型核磁共振仪的床体为对象,对驱动床体做横向运动的直流步进电机和驱动床体做纵向运动的直流伺服电机的精确控制问题进行较为深入的分析和研究。系统主要采用了ATMEL公司的Atmega128
[单片机]
基于<font color='red'>AVR单片机</font>的核磁共振仪床体检测<font color='red'>系统</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved