01第一節 知識點
我們通過定時器0的講解來實現多個定時器的定時功能。
(1)Timer0 模塊具有以下特征:
? 可通過軟件選擇,作為8 位或16 位定時器/ 計數器
? 可讀寫的寄存器
? 專用的8 位軟件可編程預分頻器
? 可選的時鐘源(內部或外部)
? 外部時鐘的邊沿選擇
? 溢出中斷
(2)TImer0工作原理
Timer0 既可用作定時器亦可用作計數器;具體的模式由TOCS 位(T0CON<5>)選擇。在定時器模式下(T0CS = 0),除非選擇了不同的預分頻值,否則,默認情況下在每個時鐘周期該模塊的計時都會遞增(見第11.3 節“預分頻器”)。如果寫入TMR0 寄存器,那么在隨后的兩個指令周期內,計時將不再遞增。用戶可通過將校正后的值寫入TMR0 寄存器來解決上述問題。通過將T0CS 位置1 選擇計數器模式。在計數器模式下, Timer0 可在RA4/T0CKI 引腳信號的每個上升沿或下降沿遞增。觸發遞增的邊沿由Timer0 時鐘源邊沿選擇位T0SE (T0CON<4>)決定。清零此位選擇上升沿遞增。下面討論外部時鐘輸入的限制條件。可以使用外部時鐘源來驅動Timer0。但是必須確保外部時鐘與內部時(TOSC)相位同步。在同步之后,定時器/ 計數器仍需要一定的延時才會引發遞增操作。
(3) 中斷
當TMR0 寄存器發生溢出時(8 位模式下,從FFh 到00h ;或16 位模式下,從FFFFh 到0000h),將產生TMR0 中斷。這種溢出會將標志位TMR0IF 置1。可以通過清零TMR0IE 位(INTCON<5>)來屏蔽此中斷。在重新允許該中斷前,必須在中斷服務程序中用軟件清
零TMR0IF 位。由于Timer0 在休眠模式下是關閉的,所以TMR0 中斷無法將處理器從休眠狀態喚醒。
(4) 定時器的時鐘選擇內部FOSC/4;
定時器的初值為0的話,8位模式, 一次中斷的時間為(1/(FOSC/4)256; 如果定時1s 中斷的計數值為n=1/((1/(FOSC/4)256);
eg: FOSC=40MHz 1s定時n=39063
02第二節 軟件設計
我們新建一個關于定時器的頭文件和一個源文件
(1) timer_config.h
/*
* File: timer_config.h
* Author: Greg
* Comments: 定時器的配置和初始化程序
* Revision history: version 1.1
*/
// This is a guard condition so that contents of this file are not included
// more than once.
#ifndef _TIMER_CONFIG_H_
#define _TIMER_CONFIG_H_
#include // include processor files - each processor file is guarded.
extern unsigned int timer0num=0;
extern unsigned int timer1num=0;
extern unsigned int timer2num=0;
void timer0_config_init(void);
void tiner1_config_init(void);
void timer2_config_init(void);
void timer3_config_init(void);
#endif /* _TIMER_CONFIG_H_ */
(2)timer_config.c
#include "timer_config.h"
void timer0_config_init(void)
{ //沒有預分頻,可以預分頻
TMR0ON=1; // enable timer0
T08BIT=1; // 8bit model
T0CS=0; //clock is selected by internal clko
PSA=1; // 未經分頻器
// 中斷timer0 使能
TMR0IE=0; // timer0 允許中斷
TMR0IF=0; // 中斷標志位清零
TMR0L=0; // 初值為0
}
void tiner1_config_init(void)
{ //沒有預分頻,可以預分頻
T1CONbits.RD16=1;// 16位操作
T1RUN=0;// 時鐘由時鐘源產生
T1OSCEN=0;
TMR1CS=0;// 內部時鐘 Fosc/4
TMR1ON=1;// timer1 使能
TMR1IE=0;// timer1 允許中斷
TMR1IF=0;
TMR1=0; //timer1 初值
}
void timer2_config_init(void)
{
T2CONbits.TMR2ON=1;// timer2使能
T2CONbits.T2CKPS=0b00; //預分頻值為1
T2CONbits.T2OUTPS=0b0000; //timer2輸出后分頻為1
TMR2=0; //timer2 初值W為0;
PR2=0xFF;// tiner2 周期寄存器的值設置為256;TMR2的值和PR2的值相等時是TMR2IF為1;
TMR2IE=0;// timer2允許中斷
TMR2IF=0;
}
void timer3_config_init(void)
{
T3CONbits.RD16=1;// 16位操作
T3CONbits.T3CKPS=0b00;// 預分頻
T3CONbits.T3SYNC=1;// 不與外部時鐘同步
T3CONbits.TMR3CS=0;// 內部時鐘
T3CONbits.TMR3ON=1;// timer3使能
TMR3=0; //timer3 初值
TMR3IE=1;// timer3允許中斷
TMR3IF=0;
}
再新建兩個關于中斷的頭文件和源文件
(3)inrt_config.h
// This is a guard condition so that contents of this file are not included
// more than once.
#ifndef _INRT_CONFIG_H_
#define _INRT_CONFIG_H_
#include // include processor files - each processor file is guarded.
#include "usart_dr.h"
void interrupt_config_init(void);
// 高級優先級中斷服務子程序 聲明
void interrupt high_priority inrt_isr_high(void);
//低級中斷服務子程序 聲明
void interrupt low_priority inrt_isr_low(void);
#endif /* _INRT_CONFIG_H_ */
(4)inrt_config.c
#include"timer_config.h"
#include "inrt_config.h"
void interrupt_config_init(void)
{
INTCONbits.GIE=1;//允許全局中斷
INTCONbits.PEIE=1;// 允許外設中斷
RCONbits.IPEN=1; // 中斷優先級使能位
RCIE=1; //USART中斷使能
RCIP=1; // USART中斷優先級高
RCIF=0;
TMR0IP=1;// timer0 設置為高級優先中斷
TMR1IP=1; //timer1 設置為高級優先級中斷
TMR2IP=1; //timer2 設置為高級優先級中斷
TMR3IP=1; //timer3 設置為高級優先級中斷
}
// 高級優先級中斷服務子程序
void interrupt high_priority inrt_isr_high(void)
{ //usart 服務
if(RCIF&&RCIE)
{
RCIF=0; // 必須先清楚RC中斷標志位
usart_send_byte(RCREG);
}
//timer 0 服務
if(TMR0IE&&TMR0IF)
{
TMR0IF=0;
timer0num++;
if(timer0num==39063)
{
usart_send_string("timer0 is count for 1s!rtn");
timer0num=0;
}
}
//timer 1 服務
if(TMR1IE&&TMR1IF)
{ // 在這里定時器的初值在初始化設置為0,因此不需要再賦初值
TMR1IF=0;
timer1num++;
if(timer1num==305) //16bits
{
usart_send_string("timer1 is count for 2s!rtn");
timer1num=0;
}
}
if(TMR2IE&&TMR2IF)
{ // 在這里定時器的初值在初始化設置為0,因此不需要再賦初值
TMR2IF=0;
timer2num++;
if(timer2num==39063)
{
usart_send_string("timer2 is count for 1s!rtn");
timer2num=0;
}
}
//timer3 服務
if(TMR3IE&&TMR3IF)
{ // 在這里定時器的初值在初始化設置為0,因此不需要再賦初值
TMR3IF=0;
timer1num++;
if(timer1num==458)//3s 16bits
{
usart_send_string("timer3 is count for 3s!rtn");
timer1num=0;
}
}
}
// 低級中斷服務程序由此處書寫
void interrupt low_priority inrt_isr_low(void)
{
;
}
現在具體的定時器和中斷的配置已經完成了,我們在主函數中使用:
注意:我們配置字沒有修改,默認前期教程的。
#include "usart_dr.h"
#include "inrt_config.h"
#include "timer_config.h"
//#include"plib/adc.h"
//#include "delays.h"
int main(void)
{
usart_port_dir_init();
usart_Config_init();
interrupt_config_init();
timer0_config_init();
tiner1_config_init();
timer2_config_init();
timer3_config_init();
usart_send_string("I love you!");
while(1)
{
}
return 0;
}
下載到開發板中測試吧,我已經測試過沒有問題。
評論
查看更多