矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
楼主: wey05

帮助新手学习单片机数码管电子钟:原理,c程序详解

  [复制链接]
 楼主| 发表于 2011-7-12 10:07:04 | 显示全部楼层
MASTER MILLWOOD:
能否把自编的头文件内容公布一下让我等学习?
"gpio.h"
"rtc0.h"                                                               
"tmr1.h"                                                               
"_7seg.h"   
多谢!
回复 支持 反对

使用道具 举报

发表于 2011-7-12 10:53:07 | 显示全部楼层
that's because it loops in the isr, if you don't clear the flag. TF2 in a 8052 has to be cleared ...
millwood 发表于 2011-4-25 00:58



  拿句四川话说:红苕粪还没拉完,就不认祖宗了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-12 12:30:09 | 显示全部楼层
拿句四川话说:红苕粪还没拉完,就不认祖宗了
kannaore 发表于 2011-7-12 10:53


别这样说,millwood老师是高手他一贯是英文贴,要多学他的编程方法
回复 支持 反对

使用道具 举报

发表于 2011-7-12 12:33:53 | 显示全部楼层
别这样说,millwood老师是高手他一贯是英文贴,要多学他的编程方法
wey05 发表于 2011-7-12 12:30



    您如果说:他祖宗本来就是洋人,就该我道歉了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-12 12:56:57 | 显示全部楼层
您如果说:他祖宗本来就是洋人,就该我道歉了。
kannaore 发表于 2011-7-12 12:33



    我根本无法肯定他是中国人,可以用中文表达问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-12 13:01:18 | 显示全部楼层
所以说millwood先生是哪国人不重要,关键还是学他的编程吧
回复 支持 反对

使用道具 举报

     
发表于 2011-7-12 13:17:59 | 显示全部楼层
millwood 兄很热心 帮顶!!
而且你今天晚上提问,一觉想来 millwood 老师就把你的问题 回复了。
回复 支持 反对

使用道具 举报

发表于 2011-7-12 17:04:46 | 显示全部楼层
Mr.millwood :
能否把自编的头文件内容公布一下让我等学习?
"gpio.h"
"rtc0.h"                                                               
"tmr1.h"                                                               
"_7seg.h"   
多谢
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:38:29 | 显示全部楼层
you will need .c and .h files to make it work.

here is main.c
  1. //time keeping on 8051
  2. //tmr0 runs as a 16-bit rtc (black roman approach)
  3. //tmr1 controls the 7-segment display

  4. #include <regx51.h>                                                                                        //we use keil c51
  5. //#include <intrins.h>
  6. #include "gpio.h"
  7. #include "rtc0.h"                                                                                        //we use rtc0
  8. #include "tmr1.h"                                                                                        //we use tmr1
  9. #include "_7seg.h"                                                                                        //we use 7seg led display

  10. //hardware configuration
  11. //end hardware configuration

  12. //global variables

  13. void time2vRAM(void) {                                                                                //convert rtc0 to vram
  14.         vRAM[7]=_rtc0.hour/10;
  15.         vRAM[6]=_rtc0.hour%10;
  16.         vRAM[5]=0x10;                                                                                        //update hour display
  17.         vRAM[4]=_rtc0.min/10;
  18.         vRAM[3]=_rtc0.min%10;                                                                        //update minute display
  19.         vRAM[2]=(_rtc0.half_sec)?0x10:0x7f;                                                //???? - blinking the half second indicator
  20.         vRAM[1]=_rtc0.sec/10;
  21.         vRAM[0]=_rtc0.sec%10;  //???????                                                 //update second display
  22. }

  23. void mcu_init(void) {
  24. }

  25. void main(void)        //???
  26. {
  27.         mcu_init();                                                                                                //reset the mcu
  28.         _7seg_init();                                                                                        //reset the 7seg display
  29.         
  30.         //set up tmr0 to run as an rtc
  31.         rtc0_init(RTC_500ms);                                                                        //reset tmr0 - period set by TMR0_PERIOD
  32.         rtc0_act(time2vRAM);                                                                        //install new isr
  33.         
  34.         //set up tmr1 to run periodically to drive the display
  35.         tmr1_init(1, TMR_1ms);                                                                         //reset tmr1 to trigger periodically
  36.         tmr1_act(_7seg_display);                                                                //install custom isr
  37.         
  38.         ei();                                                                                                        //enable global interrupt

  39.         while(1)
  40.         {
  41.                 //delay();
  42.         }
  43. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:40:09 | 显示全部楼层
here is the gpio.h (no gpio.c)
  1. //gpio header file for lpc21xx
  2. #include <intrins.h>                                                        //we use _nop_()

  3. #define IO_SET(port, bits)        port |= (bits)                //set bits on port
  4. #define IO_CLR(port, bits)        port &=~(bits)                //clear bits on port
  5. #define IO_FLP(port, bits)        port ^= (bits)                //flip bits on port

  6. #define IO_GET(port, bits)        ((port) & (bits))        //return bits on port

  7. #define IO_IN(ddr, bits)        ddr |= (bits)                //set bits as input
  8. #define IO_OUT(ddr, bits)                                                //ddr |= (bits)                //set bits as output

  9. #define NOP()                        _nop_()                                        //nop

  10. #ifndef ei
  11. #define ei()                        {EA=1;}                                        //enable interrupt
  12. #endif

  13. #ifndef di
  14. #define di()                        {EA=0;}                                        //disable interrupt
  15. #endif

  16. #define F_CPU                        1000000ul                                //f_cpu runs at 2Mhz
  17. //void (*mcu_reset)(void) = 0x0000;                                 //jump to 0x0000 -> software reset

复制代码
notice that F_CPU is set to run at 1MIPS.
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:41:50 | 显示全部楼层
here is the rtc0.h:
  1. //using tmr0 as a rtc

  2. //hardware configuration
  3. //end hardware configuration

  4. //predefined intervals for the rtc
  5. #define RTC_ms                                (F_CPU / 1000)                        //1 ms - make sure that it doesn't overflow
  6. #define RTC_10000ms                        (RTC_ms * 10000)                //how many ticks to trigger in 10000ms
  7. #define RTC_5000ms                        (RTC_ms * 5000)                        //how many ticks to trigger in 5000ms
  8. #define RTC_2000ms                        (RTC_ms * 2000)                        //how many ticks to trigger in 2000ms
  9. #define RTC_1000ms                        (RTC_ms * 1000)                        //how many ticks to trigger in 1000ms
  10. #define RTC_500ms                        (RTC_ms * 500)                        //how many ticks to trigger in 500ms
  11. #define RTC_250ms                        (RTC_ms * 250)                        //how many ticks to trigger in 250ms
  12. #define RTC_100ms                        (RTC_ms * 100)                        //how many ticks to trigger in 100ms
  13. //as we use the 16-bit timer, 64ms is the shortest you can go
  14. //as _rtc0_trigger is a long time, the longest period is 4bn ticks -> ~4000 seconds

  15. typedef struct {
  16.         unsigned char half_sec;                                                        //half second indicator - 0=1st half, 1=2nd half
  17.         unsigned char sec;
  18.         unsigned char min;
  19.         unsigned char hour;
  20.         unsigned char day;
  21. } RTC_TIME;

  22. #define RTC0_ERROR                        0                                                //RTC0 error term

  23. extern volatile RTC_TIME _rtc0;

  24. //#define RTC0_TRIGGER                RTC_1000ms                                        //configure rtc0 to trigger
  25. //initialize the timer
  26. //prescaler not used - for compatability reasons only
  27. //8-bit period

  28. void rtc0_init(unsigned long trigger);                                //how frequent is the rtc0_isr to be triggered

  29. //set up the isr handler
  30. void rtc0_act(void (*isr_ptr)(void));                                //set up the isr pointer

  31. void rtc0_update(void);                                                                //update rtc0
复制代码
here is rtc0.c
  1. #include <regx51.h>                                                //we use keil c51
  2. #include "gpio.h"
  3. #include "rtc0.h"                                                //we use tmr0 for rtc

  4. //use black roman's zero cumulative error approach
  5. //this approach will generate an output pulse whose long-term accuracy depends only on the crystal/clock source
  6. //however, it does generate jitter between clocks: the longer the periods, the bigger the jitter
  7. //as such, it is desirable in those applications that require long-term accuracy

  8. //rtc0 error term
  9. //use a positive number if rtc runs too slow;
  10. //use a negative number if rtc runs too fast

  11. //global variable
  12. void (*_rtc0_isr_ptr)(void);                        //function ptr
  13. unsigned long _rtc0_trigger=RTC_1000ms;        //rtc trigger, default to 1s
  14. unsigned long _rtc0_count=0;                        //rtc count: count up to rtc0_trigger
  15. volatile RTC_TIME _rtc0 ={                                //global time keeper for tc0
  16.         0, 58, 59, 23, 0};

  17. void _rtc0_isr(void) interrupt TF0_VECTOR {
  18.         //clear the flag                                        //automatically done by hardware
  19.         _rtc0_count+= 0x10000ul+RTC0_ERROR;        //tmr0 in 16 bit mode
  20.         if (_rtc0_count < _rtc0_trigger) return;        //life goes on
  21.         else {
  22.                 _rtc0_count-=_rtc0_trigger;                //reset _rtc0_count;
  23.                 rtc0_update();                                        //update rtc0
  24.                 _rtc0_isr_ptr();                                //call the handler
  25.         }
  26. }

  27. void rtc0_empty_ptr(void) {                                //empty ptr
  28. }

  29. //initialize the timer
  30. //prescaler not used - for compatability reasons only
  31. //8-bit period
  32. void rtc0_init(unsigned long trigger) {
  33.         TR0=0;                                                                //turn off the timer
  34.         _rtc0_isr_ptr=rtc0_empty_ptr;                //point isr to the empty handler
  35.         _rtc0_count=0;                                                //reset rtc_count
  36.         _rtc0_trigger = trigger;                        //assign the trigger
  37.         TMOD = (TMOD & 0xf0) | 0x01;                //rtc0 in mode 1: 16 bit tmr
  38.         TH0=0;                                                                //set the autoreload period
  39.         TL0=0;                                                                //reset the timer / counter
  40.         ET0=1;                                                                //enable rtc0 interrupt
  41.         TR0=1;                                                                //turn on the timer
  42. }

  43. //set up the isr handler
  44. void rtc0_act(void (*isr_ptr)(void)) {        //set up the isr pointer
  45.         _rtc0_isr_ptr=isr_ptr;
  46. }

  47. void rtc0_update(void) {
  48.         rtc0.half_sec+=1;                                        //increment half_sec indicator
  49.         if (rtc0.half_sec==2) {                                //overflown?
  50.                 rtc0.half_sec=0;                                //reset rtc0.half_sec
  51.                 rtc0.sec+=1;                                        //increment sec
  52.                 if (rtc0.sec==60) {                                //overflown?
  53.                         rtc0.sec=0;                                        //reset rtc0.sec
  54.                         rtc0.min+=1;                                //increment min
  55.                         if (rtc0.min==60) {                        //overflown?
  56.                                 rtc0.min=0;                                //reset min
  57.                                 rtc0.hour+=1;                        //increment hour
  58.                                 if (rtc0.hour==24) {        //overlown?
  59.                                         rtc0.hour=0;                //reset hour
  60.                                         rtc0.day+=1;                //increment day
  61.                                 }
  62.                         }
  63.                 }
  64.         }
  65. }

复制代码
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:42:58 | 显示全部楼层
here is tmr1 related files.

tmr1.h
  1. //initialize the timer
  2. //prescaler not used - for compatability reasons only
  3. //8-bit period

  4. #define TMR1_16BIT                                                //if use 16-bit timer

  5. //predefined intervals for the rtc
  6. #define TMR_ms                                        (F_CPU / 1000)                                //how many ticks to trigger in 1ms
  7. #define TMR_1ms                                        (TMR_ms * 1)                        //how many ticks to trigger in 1ms
  8. #define TMR_2ms                                        (TMR_ms * 2)                        //how many ticks to trigger in 2ms
  9. #define TMR_5ms                                        (TMR_ms * 5)                        //how many ticks to trigger in 5ms
  10. #define TMR_10ms                                (TMR_ms * 10)                        //how many ticks to trigger in 10ms
  11. #define TMR_20ms                                (TMR_ms * 20)                        //how many ticks to trigger in 20ms
  12. #define TMR_50ms                                (TMR_ms * 50)                        //how many ticks to trigger in 50ms

  13. #ifdef TMR1_16BIT
  14.         void tmr1_init(unsigned char prescaler, unsigned short period);
  15. #else
  16.         void tmr1_init(unsigned char prescaler, unsigned char period);
  17. #endif
  18. //set up the isr handler
  19. void tmr1_act(void (*isr_ptr)(void));        //set up the isr pointer
复制代码
tmr1.c
  1. #include <regx51.h>                                                //we use keil c51
  2. #include "gpio.h"
  3. #include "tmr1.h"                                                //we use tmr1

  4. void (*_tmr1_isr_ptr)(void);                        //function ptr
  5. unsigned short _tmr1_period;

  6. void _tmr1_isr(void) interrupt TF1_VECTOR {
  7.         //clear the flag                                        //automatically done by hardware
  8. #ifdef TMR1_16BIT
  9.         TH1+=(_tmr1_period) >> 8;                        //set the autoreload period
  10.         TL1+=_tmr1_period;                                        //reset the timer / counter
  11. #endif
  12.         _tmr1_isr_ptr();                                        //call the handler
  13. }

  14. void tmr1_empty_ptr(void) {                                //empty ptr
  15. }

  16. #ifdef TMR1_16BIT
  17. //initialize the timer
  18. //prescaler not used - for compatability reasons only
  19. //16-bit period
  20. void tmr1_init(unsigned char prescaler, unsigned short period) {
  21.         TR1=0;                                                                //turn off the timer
  22.         _tmr1_isr_ptr=tmr1_empty_ptr;                //point isr to the empty handler
  23.         TMOD = (TMOD & 0x0f) | 0x10;                //tmr1 in mode 1: 16 bit tmr
  24.         _tmr1_period=-period;
  25.         TH1=(_tmr1_period) >> 8;                        //set the autoreload period
  26.         TL1=_tmr1_period;                                        //reset the timer / counter
  27.         ET1=1;                                                                //enable tmr0 interrupt
  28.         TR1=1;                                                                //turn on the timer
  29. }
  30. #else
  31. //initialize the timer
  32. //prescaler not used - for compatability reasons only
  33. //8-bit period
  34. void tmr1_init(unsigned char prescaler, unsigned char period) {
  35.         TR1=0;                                                                //turn off the timer
  36.         _tmr1_isr_ptr=tmr1_empty_ptr;                //point isr to the empty handler
  37.         TMOD = (TMOD & 0x0f) | 0x20;                //tmr0 in mode 2: 16 bit tmr, auto reload TH0
  38.         _tmr1_period=-period;
  39.         TH1=_tmr1_period;                                        //set the autoreload period
  40.         TL1=_0;                                                                //reset the timer / counter
  41.         ET1=1;                                                                //enable tmr0 interrupt
  42.         TR1=1;                                                                //turn on the timer
  43. }
  44. #endif

  45. //set up the isr handler
  46. void tmr1_act(void (*isr_ptr)(void)) {        //set up the isr pointer
  47.         _tmr1_isr_ptr=isr_ptr;
  48. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:44:02 | 显示全部楼层
here is the 7segment related files:

_7seg.h
  1. //_7seg led display driver

  2. //hardware configuration
  3. #define _7SEG_PORT                        P2                                                                //7seg connection, active low
  4. #define _7SEG_DDR                        P2
  5. #define _7SEGs                                0xff
  6. #define _7SEG_OFF(segs)                {_7SEG_PORT= (segs);}                        //turn on segments, active low
  7. #define _7SEG_ON(segs)                {_7SEG_PORT=~(segs);}                        //turn off segments

  8. #define DIG_PORT                        P3                                                                //digits connection, active high
  9. #define DIG_DDR                                P3
  10. #define DIGs                                0xff
  11. #define DIG_ON(digs)                {DIG_PORT= (digs);}                                //turn on digs, active high
  12. #define DIG_OFF(digs)                {DIG_PORT=~(digs);}                                //turn off digs

  13. #define _7SEG_NUMBER                8                                                                //number of digits in the 7segment display
  14. //end hardware configuration

  15. extern unsigned char vRAM[8];

  16. //initialize the display
  17. void _7seg_init(void);

  18. //display the content of vRAM[8]
  19. void _7seg_display(void);
复制代码
_7seg.c
  1. #include<regx51.h>                                                                                //we use keil c51
  2. #include "gpio.h"
  3. #include "_7seg.h"                                                                                //we use _7seg display

  4. //hardware configuration
  5. //end hardware configuration

  6. //global variable
  7. //display font
  8. unsigned char code _7seg_font[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};//???????

  9. //display buffer
  10. unsigned char vRAM[8];                                                                        //display buffer

  11. //initialize the display
  12. void _7seg_init(void) {
  13.         _7SEG_OFF(_7SEGs);                                                                        //clear leds - turn off all segments
  14.         IO_OUT(_7SEG_DDR, _7SEGs);                                                        //leds as output

  15.         DIG_OFF(DIGs);                                                                                //all display off
  16.         IO_OUT(DIG_DDR, DIGs);                                                                //all digit pins as output
  17. }

  18. //display the content of vRAM[8]
  19. void _7seg_display(void) {
  20.         static unsigned char digit=0;                                                //digit to be displayed

  21.         DIG_OFF(DIGs);                                                                                //turn all digits off        
  22.         _7SEG_ON(_7seg_font[vRAM[digit]]);                                        //display the digit
  23.         DIG_ON(1<<digit);                                                                        //turn on the digit
  24.         digit+=1;                                                                                        //increment the digit
  25.         if (digit==_7SEG_NUMBER) digit=0;                                        //reset the digit
  26. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2011-7-12 21:50:22 | 显示全部楼层
本帖最后由 millwood 于 2011-7-12 21:52 编辑

some notes:

1) you will notice that each .h file has a hardware configuration section. you may need to change them based on your hardware / set-up. for example, the code is now configured to run on a 1MIPS 8051. if you run the code on a 2MIPS 8051, you will need to reconfigure F_CPU to be 2000000ul and recompile the code.

2) the font data is based on your code, which is opposite of what it ought to be. i will change that in the next run.

3) you will also notice that the code is configured to run on a chip with an output directions register. so you can easily port the code to a different mcu (avr, or a pic for example), as long as you provide the relevant .c/.c files to interface with the timers.

finally, here is the connection.

52. c51 rtc.PNG
回复 支持 反对

使用道具 举报

发表于 2011-7-12 22:16:46 | 显示全部楼层
the set-up uses tmr0 as an rtc and tmr1 to drive the display.

but you can easily port rtc0.c/.c files to rtc1.c/.h to use tmr1 as a rtc; and conversely, you can port tmr1.c/.h files to tmr0.c/.h to use tmr0 as a timer.

you can also move the segment pins (P2) / port pins (P3) to a different port - you can simply change the definitions of _7SEG_PORT and DIG_PORT in _7seg.h and recompile.

and the same _7segment code can be used to drive a 2/4/6 digit display: you can simply change the _7SEG_NUMBER definition in _7seg.h file and recompile.

this is how you should code: make your code portable (and well documented) so that the more code you write, the fewer code you write as you can reuse previously written code pieces.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2025-4-28 12:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表