小白跟做江科大51单片机之基于定时器的按键控制LED流水灯

本文详细解释了ST89C52开发板上SYSclk的工作原理,以及定时器的工作机制,包括定时器计数、溢出中断和寄存器的作用。还展示了如何利用定时器实现按键控制LED灯的左右移动,通过定时器0进行计时并根据按键输入调整LED灯的移动方向。
摘要由CSDN通过智能技术生成

图1

图2

图3

 

图4

图3表示SYSclk的工作原理:因为ST89C52开发板上的晶振为12MHZ,所以系统会产生脉冲,慢慢达到12M,达到12MHZ之后经过上面的12兆分频的话,就是1兆赫兹,1兆赫兹1个周期就是1us。联通如图所示的计数器,就是每隔1us记一次数,记到最大值,产生中断。

图·5

SYSclk:系统时钟,即晶振周期,ST89C52开发板上的晶振为12MHZ。

定时器工作原理:如图4所示左边的计数系统会发送给定时器脉冲,计数器每隔一个脉冲就会加1,但因为是之前选择定时器工作模式是模式1,所以定时器只能接受到65535,到了65535就会溢出,TF0置于1,计数器归0,产生中断。 

寄存器是连接软硬件的媒介。

在单片机中寄存器就是一段特殊的RAM存储器一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式。

寄存器相当于一个复杂机器的“操作按钮。

每个定时器主要有两种寄存器:TCON TMOD。

TCON 包括:TF, TR, IE, IT。

定时器和中断结合:时钟计数,到了时间之后,定时器发起中断请求,中断导通后实现主函数的中断,先去执行中断函数,再执行主函数。

图6


编写代码的时候,首先编写TMOD=0X01;即0000 0001,倒数第3位为0表示是定时器状态,M1和M0为01表示工作在模式1,使用16位定时器;

低四位中GATE=0表示定时器只需要图2所示的TR0控制——因为从图3可知,中间那部分为计数单元,GATE如果给0,经过非门之后,得到1,INTO是或门,所以无需考虑它,计数单元只由TR0控制。

图7

编写定时器代码首先编写:TMOD=0X01;

图8

可位寻址:表示能分开,eg:P3=0;P3_1=1;

不可位寻址:表示不能分开

TF=0;表示不会刚开始就去申请中断

TR0=1;TR表示定时器是否开始,TR=1表示开启,TR=0表示中断

图9

关于计时问题

0~65535

每隔1us计数加一

总共定时时间65535us

开始定64535离计数器溢出差值1000,所以计时时间为1ms

TH0和TL0是存储数值的,其中TH0存储的是高位,TL0存储的是低位

所以定时器存储数据代码为:

TH0=64535/256

TL0=64535%256

ET0=1;//打开定时器0 中断允许

EA=1;//打开总中断

PT=0;//优先级默认是低位

到此定时器模块函数构造完成。


time0.c代码

#include <REGX52.H>
void Timer0_Init(void)        //1毫秒@12.000MHz
{
    //这里只用到一个定时器,一个就行
    TMOD &= 0xF0;            //设置定时器模式
    TL0 = 0x18;                //设置定时初始值
    TH0 = 0xFC;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    ET0=1;         //打开定时器0 中断允许
    EA=1;          //打开总中断
    PT0=0;          //优先级为0
}

中断部分的代码不需要调用,直接就能运行,原理已在之前讲过。

time0.h包含time0.c的函数,INTRINS.H是为了使用_crol_和_cror_函数

main.c代码

#include <REGX52.H>
#include "time0.h"
#include "Delay.h"
#include <INTRINS.H>
unsigned char flag=0;
unsigned int time=0;
void main()
{
    P2=0xfe;
    Timer0_Init();
    while(1)
    {
        if(P3_1==0)
        {
            Delay(20);
            while(P3_1==0);
            Delay(20);
            time++;
            if(time%2!=0)
            {
                flag=1;
            }
            else
            {
                flag=0;
            }
        }
        
    }
}

void Timer0_Routine()  interrupt 1
{
    static unsigned int count;
    count++;
    TL0 = 0x18;                //设置定时初始值否则从0开始计数
    TH0 = 0xFC;                //设置定时初始值
    if(count>=1000)
    {
        count=0;
        if(flag!=0)
        {
            P2=_crol_(P2,1);
        }
        else
        {
            P2=_cror_(P2,1);
        }
    }
}

最终效果可实现按键控制LED灯左右移动。

基于定时器的按键控制LED流水灯


自己做了一下按第一个按键LED流水灯向右移动,按第二个按键向左移动的代码。

#include <REGX52.h>
#include <time0.h>
#include <Delay.h>


unsigned char num=0;
unsigned char flag;

void main()
{
    time0_init();
  while(1)
 {
   if(P3_1==0)
     {
         Delay(20);
         while(P3_1==0);
         Delay(20);
         flag=1;
     }
    if(P3_0==0)
     {
         Delay(20);
         while(P3_0==0);
         Delay(20);
        flag=0;
     }
 }
}

void Timer0_Routine()  interrupt 1
{
    static unsigned int count;
    count++;
    TL0 = 0x18;                //设置定时初始值否则从0开始计数
    TH0 = 0xFC;                //设置定时初始值
        if(count>=1000)
        {
            count=0;
            if(flag==1)   //LED流水灯向做右移动的代码
            {
                     if(num<8)
                     {
                         P2=~(0x01<<num);
                         num++;
                         if(num==8)
                         {
                             num=0;
                         }
                     }
          }
            else   //LED流水灯向做左移动的代码
            {  
                 if(num>0)
                 {
                     num--;
                     P2=~(0x01<<num);
                     if(num==0)
                     {
                         num=8;
                     }
                 }
            }
        }    
}

  • 31
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好,这个问题可以分为两部分来解决:独立按键的检测和LED流水灯控制。 首先,我们需要连接一个或多个LED灯到单片机的GPIO引脚上。然后,我们需要连接独立按键到另一个GPIO引脚上。 接下来,我们需要编写程序来检测按键是否按下。当按键按下时,程序需要控制LED流水灯按照一定的模式进行闪烁。 以下是一个示例程序,演示了如何使用单片机的GPIO引脚控制LED流水灯,并使用独立按键检测来控制LED流水灯的模式: ```c #include <avr/io.h> #include <util/delay.h> #define LED_PORT PORTB #define LED_DDR DDRB #define LED_PINS 0b11111111 #define KEY_PORT PORTC #define KEY_DDR DDRC #define KEY_PIN 0 void led_init() { LED_DDR = LED_PINS; } void led_on(uint8_t pin) { LED_PORT |= (1 << pin); } void led_off(uint8_t pin) { LED_PORT &= ~(1 << pin); } void key_init() { KEY_PORT |= (1 << KEY_PIN); KEY_DDR &= ~(1 << KEY_PIN); } int key_pressed() { return !(KEY_PIN & (1 << KEY_PIN)); } int main() { led_init(); key_init(); uint8_t pattern = 0b00000001; while (1) { if (key_pressed()) { pattern <<= 1; if (!pattern) { pattern = 0b00000001; } } for (uint8_t i = 0; i < 8; i++) { if (pattern & (1 << i)) { led_on(i); } else { led_off(i); } } _delay_ms(100); } return 0; } ``` 在这个示例程序中,我们使用了AVR单片机控制LED流水灯和独立按键。首先,我们定义了LED引脚和独立按键引脚的端口和引脚号码。然后,我们编写了一些辅助函数来控制LED的开关状态以及按键的检测。 在主函数中,我们初始化了LED和按键的GPIO引脚,并设置了初始的LED模式。然后,我们进入了一个循环中,不断检测按键是否按下,并根据按键的状态来改变LED的模式。 在LED模式改变的过程中,我们使用位移运算和位运算来控制LED的开关状态。最后,我们使用延时函数来控制LED的闪烁频率。 注意,这个示例程序只是一个简单的演示,实际应用中需要考虑更多的因素,例如按键去抖动、LED流水灯的模式设计等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值