snifer

【技术分享】【原创】基于AT89C52的一个速度计数器的设计过程

0
阅读(15049)

前面说到要写一下嵌入式HCS12的调试的文章,最近实验室关门了,进不去,不好调试,等段时间吧,写一个简单的基于AT89C52的一个速度计数器的设计过程。

设计要求:利用单片机实现的自行车里程/速度计能自动显示自行车行驶的总里程数及自行车行驶速度,具有超速信号提醒功能,里程数据自动记忆。也可应用于电动自行车、摩托车、汽车等机动车仪表上。

1. 总体设计

    控制器采用AT89C52单片机,速度及里程传感器采用霍尔元件,显示器通过AT89C52的P0口和P2口扩展。外部存储器采用E2PROM存储器AT24C01,用于存储里程和速度等数据。并用控制器来控制里程/速度指示灯,里程指示灯亮时,显示里程;速度指示灯亮时,显示速度。超速报警采用扬声器,用一个发光二极管来配合扬声器,扬声器响时,二极管亮,表明超速。  

2. 硬件电路设计


    电路原理图如下页图所示。P0口和P2口用于七段LED显示器的段码及扫描输出。在显示里程时,第三位小数点用P3.7口()控制点亮。P1.0口和P1.1口分别用于显示里程状态和速度状态。P1.2,P1.3,P1.6和P1.7口分别用于设置轮圈的大小。P3.0口的开关用于确定显示的方式。当开关闭合时,显示速度;断开时,显示里程。外中断用于对轮子圈数的计数输入,轮子每转一圈,霍尔传感器输出一个低电平脉冲。外中断用于控制定时器T1的启停,当输入为0时关闭定时器。此控制信号是将轮子圈数的计数脉冲经二分频后形成,这样,每次定时器T1的开启时间正好为轮子转一圈的时间,根据轮子的周长就可以计算出自动车的速度。P1.4口和P1.5口用于E2PROM存储器24C01的存取控制。11脚(TXD)输出用于速度超速时的报警。 



3. 软件设计

软件主要包括:主程序、初始化程序、里程计数子程序、数据处理子程序、计数器中断服务程序、E2PROM存取程序、显示子程序。 

(1)主程序

     根据P0口的开关状态切换显示状态,即选择里程显示和速度显示。其流程图如右图所示。



程序如下:

    ORG    0000H  

       LJMP START       ; 跳至主程序

       ORG  0003H           ; 外中断0中断程序入口

       LJMP  INTEX0         ; 跳至INTEX0中断服务程序

       ORG  000BH          ; 定时器T0中断程序入口

       RETT1                       ; 中断返回

       ORG   0013H           ; 外中断1中断入口

       LJMP  INTEX1      ; 跳至INTEX1中断服务程序

       ORG   001BH        ; 定时器T1中断程序入口

       LJMP  INTT1        ; 跳至INTT1中断服务程序

       ORG   0023H     ; 串口中断入口地址

       RET1                       ; 中断返回

       ORG   002BH      ; 定时器T2中断入口地址

       RET1                      ; 中断返回

       ORG    0050H 

     START:  LCALL  CLEARMEN    ; 上电初始化

    START1: JB  P0.4, DISPLAYS      ; P0.4=1,则显示里程

       LCALL   DISPLAYV     ; P0.4=0,显示速度

    START2: SJMP   START          ; 转START循环

(2)初始化程序

    初始化程序主要功能是将T1设为外部控制定时器方式,外中断         及        设为边沿触发方式,将部分内存单元清0,设置车轮周长值,开中断、启动定时器,将AT24C01中的数据调入内存中,设置车轮圈出错处理程序。

  程序如下:

CLEARMEN:  MOV    TMOD, #90      ; T1为16位外部控制定时器

                  MOV     SP, #75H       ; 堆栈在75H开始

                  SETB     PX0           ; 外中断0优先级为1

                  SETB      IT0             ; 外中断0用边沿触发

                  SETB      IT1             ; 外中断1用边沿触发

                  MOV      A, #00H       ; 清A

                  MOV      20H, A        ; 清内存中特定单元

                  MOV      6CH, A       

                  MOV      6DH, A       

                  MOV      70H, A        

                  MOV      71H, A        

                  MOV      72H, A        

                  MOV      73H, A        

                  MOV      60H, A         

                                MOV      61H, A        

                  MOV      62H, A        

                  MOV      63H, A        ; 清内存中特定单元

                  DEC      A                            ; A为#0FFH

                  MOV      68H,A        ; 内存置数据#0FFH

                  MOV      69H,A        ; 内存置数据#0FFH

                  MOV      6AH,A        ; 内存置数据#0FFH

                  MOV     6BH,A        ; 内存置数据#0FFH

                  MOV    P1, A          ; P1口置1

        CLEAR1:  JB    P1.2, KEY1      ; 根据P1.2, P1.3, P1.6, P1.7设置状态

                                                                              在21H地址单元设置自行车周长值

                  MOV     21H,#0FH    ; 22英寸自行车周长系数

                  LJMP     CLEAR2      ; 转CLEAR2

             KEY1:  JB    P1.3, KEY2        

  MOV     21H, #12H     ; 24英寸自行车周长系数

  LJMP     CLEAR2      ; 转CLEAR2

             KEY2:  JB    P1.6,KEY3        

  MOV     21H,#14H    ; 26英寸自行车周长系数

  LJMP    CLEAR2      ; 转CLEAR2

             KEY3:  JB    P1.7,ERR        

  MOV      21H,#19H    ; 28英寸自行车周长系数

        CLEAR2:  SETB     TR1           ; 开定时器开关T1

                  SETB     EA                            ; 开中断允许

                                SETB     EX0                         ; 开外中断

  SETB      ET1                         ; 开定时中断T1

  SETB     P3.1                         ; 关报警器

  LCALL    VIICREAD             ; 将E2PROM中原里程数据调入内存

  RET                                    ; 子程序返回

               ERR:  CLP       P3.1           ; 轮周长设置出错,LED灯闪烁提醒

  LCALL    DLSS5                    ; 延时

  LJMP     CLEAR1              ; 重新初始化,等待轮周长设置开关合上

(3)里程计数子程序

    外中断         服务程序用于对输入的车轮圈数脉冲进行计数,为十六进制计数,用片内RAM的60H单元存储计数值的低位,62H存储高位,计数一次后,对里程数据进行一次存储。

程序如下:

       INTEX0:  PUSH  ACC           ; 累加器堆栈保护

  PUSH  PSW           ; 状态字堆栈保护

  INC    60H           ; 圈加1

  MOV   A, #00H     ; 清A

                CJNE   A, 60H,INTEX0OUT      ; 计数没溢出转IN0OUT

                INC    61H           ; 溢出进位(61H加1)

                CJNE   A, 61H, INTEX0OUT     ; 计数没溢出转IN0OUT

                INC    62H           ; 溢出进位(62H加1)

       IN0OUT:  LCALL  VIICWRITE     ; 里程数据存入E2PROM

                SETB   EX1                         ; 开外中断1

                 POP    PSW           ; 状态字恢复

                 POP    ACC                        ; 累加器恢复

  RET1                    ;

(4)数据处理子程序

     外中断服务程序用于处理轮子转动一圈后的计时数据,当标志位(00H)为1时,说明计数器溢出,放入最大值0FFH;当标志位为0时,将计数单元(TL1,TH1,6CH, 60H)的值放入68H~6BH单元。

程序如下:

            INTEX1:  PUSH  ACC            ; 累加器堆栈保护

  PUSH  PSW           ; 状态字堆栈保护

                  CLR   EX1            ; 关外中断1

                   JNB   00H, INTEX11      ; 溢出标志为0转INTEX11

                      MOV  TL1, #0FFH          ; 溢出时,计时单元赋#FFH(显示速度为0)

                  MOV  TH1, #0FFH           

                  MOV  6CH, #0FFH           

  MOV  6DH, #0FFH           

         INTEX11:  MOV  68H, TL1        ; 将时间计数值存入暂存单元68H~6BH

                  MOV  69H, TH1              

  MOV  6AH, 6CH              

  MOV  6BH, 6DH             

  MOV  A, #00H         ; 清A

  MOV  TL1, A           ; 计时单元置0

  MOV  TH1, A                

  MOV  6CH, A                 

  MOV  6DH, A                 

  CLR   00H              ; 清溢出标志

  POP   PSW           ; 状态字恢复

  POP   ACC          ; 累加器恢复

  RET1                    ; 中断返回


呵呵,就是这样,感觉这个系统做的比较不错,适合初学者,谢谢大家投票啊