本文将详细介绍如何配置PIC16F1719单片机的时钟、定时器以及中断功能,以实现定时控制LED的简单任务。我们使用了MPLAB XC8编译器,并通过配置寄存器设置和中断服务程序(ISR)来控制LED在固定的时间间隔内闪烁。
配置位设置是PIC16F1719固件开发中非常重要的一部分,它定义了系统硬件和关键功能的行为。在此代码中,我们配置了PIC16F1719的时钟源、看门狗定时器等功能。代码如下所示:
c/* PIC16F1719 配置位设置 */
#pragma config FOSC = INTOSC /* 振荡器选择位 (INTOSC 振荡器: CLKIN 引脚上的 I/O 功能) */
#pragma config WDTE = OFF /* 看门狗定时器使能 (WDT 禁用) */
#pragma config PWRTE = OFF /* 上电定时器使能 (PWRT 禁用) */
#pragma config MCLRE = ON /* MCLR 引脚功能选择 (MCLR/VPP 引脚功能为 MCLR) */
#pragma config CP = OFF /* 闪存程序存储器代码保护 (程序存储器代码保护禁用) */
#pragma config BOREN = OFF /* 低电压复位使能 (低电压复位禁用) */
#pragma config CLKOUTEN = OFF /* 时钟输出使能 (CLKOUT 功能禁用) */
#pragma config IESO = ON /* 内外部切换模式 (内外部切换模式使能) */
#pragma config FCMEN = ON /* 故障安全时钟监控器使能 (故障安全时钟监控器使能) */
#pragma config WRT = OFF /* 闪存自写保护 (写保护关闭) */
#pragma config PPS1WAY = OFF /* 外设引脚选择单向控制 (PPSLOCK 位可以通过软件反复设置和清除) */
#pragma config ZCDDIS = ON /* 零交叉检测禁用 (ZCD 禁用) */
#pragma config PLLEN = ON /* 锁相环使能 (4x PLL 使能) */
#pragma config STVREN = ON /* 栈溢出/下溢复位使能 */
#pragma config BORV = LO /* 低电压复位电压选择 (选择低触发点) */
#pragma config LPBOR = OFF /* 低功率低电压复位禁用 */
#pragma config LVP = ON /* 低电压编程使能 */
这段配置代码主要实现了以下功能:
接下来,我们定义了系统振荡器频率_XTAL_FREQ
为32MHz,这对于延迟函数和定时器配置至关重要。
c#define _XTAL_FREQ (32000000ul)
在初始化过程中,OSCCON寄存器被设置为使用8MHz内部振荡器,并启用4x PLL,以使系统频率达到32MHz。
为了实现定时控制LED的闪烁,定时器1被设置为1ms的时间间隔。我们通过以下步骤配置定时器1:
TMR1 = 65536 - (32000000 / 4 / 1000)
设定定时器初始值,确保定时器每隔1ms溢出一次。c// prescale = 1
T1CONbits.T1CKPS = 0b00;
// Set TMR1 to initial value for 1s interval
TMR1 = 65536 - (32000000 / 4 / 1000); // 1ms interval (adjust according to actual requirement)
// enable timer1
T1CONbits.TMR1ON = 1;
我们启用了定时器1中断,并在中断服务程序中控制LED的闪烁。为了确保中断正常工作,我们需要如下步骤:
PIE1bits.TMR1IE = 1
。INTCONbits.PEIE = 1
和 INTCONbits.GIE = 1
。中断服务程序通过检查定时器1的中断标志位PIR1bits.TMR1IF
来确定是否发生了定时器溢出,并切换LED的状态:
cvoid __interrupt() isr(void){
static unsigned char ledState = 0;
if (PIR1bits.TMR1IF) {
PIR1bits.TMR1IF = 0;
// Toggle LED
if (ledState) {
LATDbits.LATD1 = 0;
} else {
LATDbits.LATD1 = 1;
}
ledState = !ledState;
// Reload Timer1
TMR1 = 65536 - (32000000 / 4 / 1000); // 1ms interval
}
}
主程序中的主循环(while(1)
)并不执行任何操作,所有的处理都发生在中断服务程序中。我们只是让主循环保持运行,等待中断的触发。
c
/* PIC16F1719 配置位设置 */
#pragma config FOSC = INTOSC /* 振荡器选择位 (INTOSC 振荡器: CLKIN 引脚上的 I/O 功能) */
#pragma config WDTE = OFF /* 看门狗定时器使能 (WDT 禁用) */
#pragma config PWRTE = OFF /* 上电定时器使能 (PWRT 禁用) */
#pragma config MCLRE = ON /* MCLR 引脚功能选择 (MCLR/VPP 引脚功能为 MCLR) */
#pragma config CP = OFF /* 闪存程序存储器代码保护 (程序存储器代码保护禁用) */
#pragma config BOREN = OFF /* 低电压复位使能 (低电压复位禁用) */
#pragma config CLKOUTEN = OFF /* 时钟输出使能 (CLKOUT 功能禁用。CLKOUT 引脚上的 I/O 或振荡器功能) */
#pragma config IESO = ON /* 内外部切换模式 (内外部切换模式使能) */
#pragma config FCMEN = ON /* 故障安全时钟监控器使能 (故障安全时钟监控器使能) */
#pragma config WRT = OFF /* 闪存自写保护 (写保护关闭) */
#pragma config PPS1WAY = OFF /* 外设引脚选择单向控制 (PPSLOCK 位可以通过软件反复设置和清除) */
#pragma config ZCDDIS = ON /* 零交叉检测禁用 (ZCD 禁用。ZCD 可以通过设置 ZCDCON 的 ZCDSEN 位来启用) */
#pragma config PLLEN = ON /* 锁相环使能 (4x PLL 使能) */
#pragma config STVREN = ON /* 栈溢出/下溢复位使能 (栈溢出或下溢将导致复位) */
#pragma config BORV = LO /* 低电压复位电压选择 (低电压复位电压 (Vbor),选择低触发点。) */
#pragma config LPBOR = OFF /* 低功率低电压复位 (低功率低电压复位禁用) */
#pragma config LVP = ON /* 低电压编程使能 (低电压编程使能) */
/* 定义系统振荡器频率 */
#define _XTAL_FREQ (32000000ul)
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//counter variable
int count = 0;
void main(void) {
unsigned char index = 0;
/* 程序初始化设置 */
OSCCON = 0xF0; /* 设置 INTOSC 为 8MHz,并使用 4xPLL,使系统振荡器达到 32MHz */
INTCON = 0; /* 禁用所有中断源 */
PIE1 = 0;
PIE2 = 0;
PIE3 = 0;
// Allow PLL startup time ~2 ms
__delay_ms(10);
ANSELA = 0x00; // 将所有A端口引脚设置为数字模式
ANSELB = 0x00; // 将所有B端口引脚设置为数字模式
ANSELC = 0x00; // 将所有C端口引脚设置为数字模式
// Set PIN D1 as output
TRISDbits.TRISD1 = 0;
// Turn off LED
LATDbits.LATD1 = 0;
// Setup PORTD
TRISD = 0;
ANSELD = 0;
// prescale = 1
T1CONbits.T1CKPS = 0b00;
// Set TMR1 to initial value for 1s interval
TMR1 = 65536 - (32000000 / 4 / 1000); // 1ms interval (adjust according to actual requirement)
// enable timer1
T1CONbits.TMR1ON = 1;
// enable timer1 interrupt
PIE1bits.TMR1IE = 1;
INTCONbits.PEIE = 1; // 使能外设中断
INTCONbits.GIE = 1; // 使能全局中断
while (1) {
// Main loop does nothing, all action in ISR
}
}
void __interrupt() isr(void){
static unsigned char ledState = 0;
if (PIR1bits.TMR1IF) {
PIR1bits.TMR1IF = 0;
// Toggle LED
if (ledState) {
LATDbits.LATD1 = 0;
} else {
LATDbits.LATD1 = 1;
}
ledState = !ledState;
// Reload Timer1
TMR1 = 65536 - (32000000 / 4 / 1000); // 1ms interval
}
}
通过这种方式,我们可以使用PIC16F1719的定时器和中断功能来控制LED每隔1ms闪烁一次。这个项目展示了如何通过简单的定时器中断机制来处理时间敏感任务,对于初学者理解PIC单片机的定时器和中断机制非常有帮助**。**
本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!