2024-09-07
单片机
00

目录

使用PIC16F1719进行定时器中断控制LED闪烁
前言
开发环境和硬件需求
配置位设置
系统时钟设置
IO口配置
定时器0设置
定时器中断处理
延时功能
全部代码
总结

使用PIC16F1719进行定时器中断控制LED闪烁

前言

在嵌入式系统开发中,定时器是非常重要的外设之一。通过定时器中断,我们可以精确地控制任务的执行时间,比如LED的闪烁频率。本文介绍了如何使用PIC16F1719微控制器的定时器0来控制LED的闪烁。

开发环境和硬件需求

  • PIC16F1719微控制器
  • MPLAB X IDE开发环境
  • XC8编译器
  • 一个LED和电阻
  • 其他基本开发工具(例如开发板、仿真器、示波器等)

配置位设置

在编写程序之前,首先需要设置PIC的配置位(Configuration Bits)。配置位用于配置微控制器的系统行为,比如振荡器的类型、看门狗定时器、低电压复位等。在本文的代码中,配置位的设置如下:

c
#pragma config FOSC = INTOSC /* 内部振荡器,使用内部时钟 */ #pragma config WDTE = OFF /* 禁用看门狗定时器 */ #pragma config PWRTE = OFF /* 禁用上电定时器 */ #pragma config MCLRE = ON /* MCLR 引脚功能使能 */ #pragma config CP = OFF /* 禁用代码保护 */ #pragma config BOREN = OFF /* 禁用低电压复位 */ #pragma config CLKOUTEN = OFF /* 禁用时钟输出 */ #pragma config IESO = ON /* 启用内部/外部切换模式 */ #pragma config FCMEN = ON /* 启用故障安全时钟监控 */ #pragma config WRT = OFF /* 禁用写保护 */ #pragma config PPS1WAY = OFF /* 允许多次更改外设引脚选择 */ #pragma config ZCDDIS = ON /* 禁用零交叉检测 */ #pragma config PLLEN = ON /* 启用锁相环(PLL) */ #pragma config STVREN = ON /* 启用栈溢出/下溢复位 */ #pragma config BORV = LO /* 选择低电压复位触发点 */ #pragma config LPBOR = OFF /* 禁用低功耗低电压复位 */ #pragma config LVP = ON /* 启用低电压编程 */

系统时钟设置

为了使系统时钟达到32MHz,我们使用了内部振荡器(INTOSC)并启用了4倍的PLL(Phase-Locked Loop)。使用下面的代码可以完成系统时钟的配置:

c
OSCCON = 0xF0; // 设置INTOSC为8MHz,使用4x PLL,最终系统时钟为32MHz

IO口配置

在这段代码中,我们使用了RD1引脚来控制LED的状态,因此需要将其配置为输出模式:

c
TRISDbits.TRISD1 = 0; // 设置RD1为输出 LATDbits.LATD1 = 0; // 初始LED关闭

此外,我们将所有模拟输入引脚设置为数字模式以避免干扰:

c
ANSELA = 0x00; // 将所有A端口引脚设置为数字模式 ANSELB = 0x00; // 将所有B端口引脚设置为数字模式 ANSELC = 0x00; // 将所有C端口引脚设置为数字模式

定时器0设置

定时器0是8位定时器,使用内部时钟并配置为256分频:

c
OPTION_REGbits.TMR0CS = 0; // 使用内部时钟 OPTION_REGbits.PSA = 0; // 启用预分频器 OPTION_REGbits.PS0 = 1; // 预分频器设置为256 OPTION_REGbits.PS1 = 1; OPTION_REGbits.PS2 = 1; TMR0 = 0; // 初始化定时器0

在这里,定时器溢出后会触发中断,因此我们需要使能定时器0中断:

c
INTCONbits.TMR0IE = 1; // 使能定时器0中断 INTCONbits.PEIE = 1; // 使能外设中断 INTCONbits.GIE = 1; // 使能全局中断

定时器中断处理

在中断服务程序中,我们对计数器进行累加,当计数器达到一定值(比如122次溢出,对应约1秒时间)时,切换LED的状态,并重置计数器:

c
void __interrupt() timer0_isr(void) { if (INTCONbits.TMR0IF) { INTCONbits.TMR0IF = 0; // 清除中断标志 count++; // 增加计数 if (count == 122) { // 当计数器达到122时 LATDbits.LATD1 ^= 1; // 切换LED状态 count = 0; // 重置计数 } } }

延时功能

为了确保系统在启动时稳定工作,我们使用了一个小的延时函数来等待PLL的启动时间:

c
__delay_ms(10); // 允许PLL启动时间大约2ms

全部代码

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端口引脚设置为数字模式 // 配置D1为输出 TRISDbits.TRISD1 = 0; LATDbits.LATD1 = 0; // 配置定时器0 OPTION_REGbits.TMR0CS = 0; // 使用内部时钟 OPTION_REGbits.PSA = 0; // 使用预分频器 OPTION_REGbits.PS0 = 1; // 预分频器 256 OPTION_REGbits.PS1 = 1; OPTION_REGbits.PS2 = 1; TMR0 = 0; // 定时器0计数器初始化 // 使能定时器中断 INTCONbits.TMR0IE = 1; INTCONbits.TMR0IF = 0; INTCONbits.PEIE = 1; // 使能外设中断 INTCONbits.GIE = 1; // 使能全局中断 while (1) { } } void __interrupt() timer0_isr(void) { // 检查是否是 Timer0 溢出中断 if (INTCONbits.TMR0IF) { // 重置 Timer0 溢出标志 INTCONbits.TMR0IF = 0; // 增加计数 count++; // 1 秒周期 if (count == 122) { LATDbits.LATD1 ^= 1; // 切换LED状态 count = 0; // 重置计数 } // 重装载 Timer0 (根据需要,可以添加) } }

总结

通过本文的代码,我们可以使用PIC16F1719的定时器0实现精确的时间控制,达到LED每秒闪烁一次的效果。通过定时器中断,避免了轮询的方式,提高了系统的效率和实时性。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Dong

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!