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.