wey05 发表于 2011-7-12 10:07:04

MASTER MILLWOOD:
能否把自编的头文件内容公布一下让我等学习?
"gpio.h"
"rtc0.h"                                                               
"tmr1.h"                                                               
"_7seg.h"   
多谢!

kannaore 发表于 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 http://www.crystalradio.cn/bbs/images/common/back.gif


拿句四川话说:红苕粪还没拉完,就不认祖宗了

wey05 发表于 2011-7-12 12:30:09

拿句四川话说:红苕粪还没拉完,就不认祖宗了
kannaore 发表于 2011-7-12 10:53 http://www.crystalradio.cn/bbs/images/common/back.gif

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

kannaore 发表于 2011-7-12 12:33:53

别这样说,millwood老师是高手他一贯是英文贴,要多学他的编程方法
wey05 发表于 2011-7-12 12:30 http://www.crystalradio.cn/bbs/images/common/back.gif


    您如果说:他祖宗本来就是洋人,就该我道歉了。

wey05 发表于 2011-7-12 12:56:57

您如果说:他祖宗本来就是洋人,就该我道歉了。
kannaore 发表于 2011-7-12 12:33 http://www.crystalradio.cn/bbs/images/common/back.gif


    我根本无法肯定他是中国人,可以用中文表达问题

wey05 发表于 2011-7-12 13:01:18

所以说millwood先生是哪国人不重要,关键还是学他的编程吧

xiaomu 发表于 2011-7-12 13:17:59

millwood 兄很热心 帮顶!!
而且你今天晚上提问,一觉想来 millwood 老师就把你的问题 回复了。

清风车影18 发表于 2011-7-12 17:04:46

Mr.millwood :
能否把自编的头文件内容公布一下让我等学习?
"gpio.h"
"rtc0.h"                                                               
"tmr1.h"                                                               
"_7seg.h"   
多谢

millwood 发表于 2011-7-12 21:38:29

you will need .c and .h files to make it work.

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

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

//hardware configuration
//end hardware configuration

//global variables

void time2vRAM(void) {                                                                                //convert rtc0 to vram
        vRAM=_rtc0.hour/10;
        vRAM=_rtc0.hour%10;
        vRAM=0x10;                                                                                        //update hour display
        vRAM=_rtc0.min/10;
        vRAM=_rtc0.min%10;                                                                        //update minute display
        vRAM=(_rtc0.half_sec)?0x10:0x7f;                                                //???? - blinking the half second indicator
        vRAM=_rtc0.sec/10;
        vRAM=_rtc0.sec%10;//???????                                                 //update second display
}

void mcu_init(void) {
}

void main(void)      //???
{
        mcu_init();                                                                                                //reset the mcu
        _7seg_init();                                                                                        //reset the 7seg display
      
        //set up tmr0 to run as an rtc
        rtc0_init(RTC_500ms);                                                                        //reset tmr0 - period set by TMR0_PERIOD
        rtc0_act(time2vRAM);                                                                        //install new isr
      
        //set up tmr1 to run periodically to drive the display
        tmr1_init(1, TMR_1ms);                                                                         //reset tmr1 to trigger periodically
        tmr1_act(_7seg_display);                                                                //install custom isr
      
        ei();                                                                                                        //enable global interrupt

        while(1)
        {
                //delay();
        }
}

millwood 发表于 2011-7-12 21:40:09

here is the gpio.h (no gpio.c)//gpio header file for lpc21xx
#include <intrins.h>                                                        //we use _nop_()

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

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

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

#define NOP()                        _nop_()                                        //nop

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

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

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

notice that F_CPU is set to run at 1MIPS.

millwood 发表于 2011-7-12 21:41:50

here is the rtc0.h://using tmr0 as a rtc

//hardware configuration
//end hardware configuration

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

typedef struct {
        unsigned char half_sec;                                                        //half second indicator - 0=1st half, 1=2nd half
        unsigned char sec;
        unsigned char min;
        unsigned char hour;
        unsigned char day;
} RTC_TIME;

#define RTC0_ERROR                        0                                                //RTC0 error term

extern volatile RTC_TIME _rtc0;

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

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

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

void rtc0_update(void);                                                                //update rtc0
here is rtc0.c#include <regx51.h>                                                //we use keil c51
#include "gpio.h"
#include "rtc0.h"                                                //we use tmr0 for rtc

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

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

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

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

void rtc0_empty_ptr(void) {                                //empty ptr
}

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

//set up the isr handler
void rtc0_act(void (*isr_ptr)(void)) {        //set up the isr pointer
        _rtc0_isr_ptr=isr_ptr;
}

void rtc0_update(void) {
        rtc0.half_sec+=1;                                        //increment half_sec indicator
        if (rtc0.half_sec==2) {                                //overflown?
                rtc0.half_sec=0;                                //reset rtc0.half_sec
                rtc0.sec+=1;                                        //increment sec
                if (rtc0.sec==60) {                                //overflown?
                        rtc0.sec=0;                                        //reset rtc0.sec
                        rtc0.min+=1;                                //increment min
                        if (rtc0.min==60) {                        //overflown?
                                rtc0.min=0;                                //reset min
                                rtc0.hour+=1;                        //increment hour
                                if (rtc0.hour==24) {        //overlown?
                                        rtc0.hour=0;                //reset hour
                                        rtc0.day+=1;                //increment day
                                }
                        }
                }
        }
}

millwood 发表于 2011-7-12 21:42:58

here is tmr1 related files.

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

#define TMR1_16BIT                                                //if use 16-bit timer

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

#ifdef TMR1_16BIT
        void tmr1_init(unsigned char prescaler, unsigned short period);
#else
        void tmr1_init(unsigned char prescaler, unsigned char period);
#endif
//set up the isr handler
void tmr1_act(void (*isr_ptr)(void));        //set up the isr pointer
tmr1.c#include <regx51.h>                                                //we use keil c51
#include "gpio.h"
#include "tmr1.h"                                                //we use tmr1

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

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

void tmr1_empty_ptr(void) {                                //empty ptr
}

#ifdef TMR1_16BIT
//initialize the timer
//prescaler not used - for compatability reasons only
//16-bit period
void tmr1_init(unsigned char prescaler, unsigned short period) {
        TR1=0;                                                                //turn off the timer
        _tmr1_isr_ptr=tmr1_empty_ptr;                //point isr to the empty handler
        TMOD = (TMOD & 0x0f) | 0x10;                //tmr1 in mode 1: 16 bit tmr
        _tmr1_period=-period;
        TH1=(_tmr1_period) >> 8;                        //set the autoreload period
        TL1=_tmr1_period;                                        //reset the timer / counter
        ET1=1;                                                                //enable tmr0 interrupt
        TR1=1;                                                                //turn on the timer
}
#else
//initialize the timer
//prescaler not used - for compatability reasons only
//8-bit period
void tmr1_init(unsigned char prescaler, unsigned char period) {
        TR1=0;                                                                //turn off the timer
        _tmr1_isr_ptr=tmr1_empty_ptr;                //point isr to the empty handler
        TMOD = (TMOD & 0x0f) | 0x20;                //tmr0 in mode 2: 16 bit tmr, auto reload TH0
        _tmr1_period=-period;
        TH1=_tmr1_period;                                        //set the autoreload period
        TL1=_0;                                                                //reset the timer / counter
        ET1=1;                                                                //enable tmr0 interrupt
        TR1=1;                                                                //turn on the timer
}
#endif

//set up the isr handler
void tmr1_act(void (*isr_ptr)(void)) {        //set up the isr pointer
        _tmr1_isr_ptr=isr_ptr;
}

millwood 发表于 2011-7-12 21:44:02

here is the 7segment related files:

_7seg.h//_7seg led display driver

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

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

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

extern unsigned char vRAM;

//initialize the display
void _7seg_init(void);

//display the content of vRAM
void _7seg_display(void);
_7seg.c#include<regx51.h>                                                                                //we use keil c51
#include "gpio.h"
#include "_7seg.h"                                                                                //we use _7seg display

//hardware configuration
//end hardware configuration

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

//display buffer
unsigned char vRAM;                                                                        //display buffer

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

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

//display the content of vRAM
void _7seg_display(void) {
        static unsigned char digit=0;                                                //digit to be displayed

        DIG_OFF(DIGs);                                                                                //turn all digits off      
        _7SEG_ON(_7seg_font]);                                        //display the digit
        DIG_ON(1<<digit);                                                                        //turn on the digit
        digit+=1;                                                                                        //increment the digit
        if (digit==_7SEG_NUMBER) digit=0;                                        //reset the digit
}

millwood 发表于 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.

millwood 发表于 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.
页: 1 2 3 4 5 6 7 8 [9] 10 11 12 13 14 15 16 17
查看完整版本: 帮助新手学习单片机数码管电子钟:原理,c程序详解