NY8A050D九齐EPROM 8位MCU应用指南:GPIO初始化、高低电平、定时器中断及看门狗设置等功能详解
一、初始化GPIO
1. 设置输入输出 — IOSTB
(1)IOSTB 解释
//IOSTB 初始值0x3F 即默认全为输入模式
//1-输入 0-输出
#define C_PB0_Input 0x01
#define C_PB1_Input 0x02
....
#define C_PB6_Input 0x20
//输出都是0x00
#define C_PB##_Output 0x00
#define C_PB_Input 0x3F
#define C_PB_Output 0x00
(2)IOSTB 使用
//方式1:宏定义表示
IOSTB = C_PB4_Input | C_PB1_Input;//设置PB4和PB1为输入模式,其他则为输出模式
//方式2:使用十六或二进制表示
IOSTB = 0x1F; //设置PB0-PB4为输入模式,PB5为输出模式
IOSTB = 0x00; //设置PB0-PB5为输出模式
IOSTB = 0B11001001; //PB5421 输出
2. 设置高低电平 — PORTB
(1)PORTB 解释
//PORTB 初始值0x00 即默认全为低电平
//1-高电平 0-低电平
#define C_PB_Data 0x3F
#define C_PB5_Data 0x20
#define C_PB4_Data 0x10
#define C_PB3_Data 0x08
#define C_PB2_Data 0x04
#define C_PB1_Data 0x02
#define C_PB0_Data 0x01
(2)PORTB 使用
//方式1:宏定义表示
PORTB = C_PB5_Data | C_PB3_Data;//设置PB5和PB3为高电平
//方式2:使用十六或二进制表示
PORTB = 0x00; //全输出低电平
PORTB = 0xFF; //全输出高电平
PORTB = 0x05; //PB2,PB0输出高电平
PORTB = 0B11001001; //PB5421低电平
3.上拉电阻 — BPHCON
(1)BPHCON 解释
//BPHCON 初始值0x3F 默认全禁用
//1-禁用上拉 0-启用上拉
#define C_PB_PHB 0x3F
#define C_PB5_PHB 0x20
#define C_PB4_PHB 0x10
#define C_PB3_PHB 0x08
#define C_PB2_PHB 0x04
#define C_PB1_PHB 0x02
#define C_PB0_PHB 0x01
(2)BPHCON 使用
//方式1:宏定义表示
BPHCON = (unsigned char)~C_PB4_PHB; //PB4上拉,其他禁用
BPHCON = (unsigned char)~(C_PB4_PHB | C_PB2_PHB); //PB42上拉,其他禁用
//方式2:使用十六或二进制表示
BPHCON = 0B00101101;//PB41上拉
BPHCON = 0x1F;//PB5上拉
BPHCON = 0x00;//PB0-PB5上拉
3.下拉电阻 — BPLCON
注:
(1)BPLCON 解释
//BPLCON 初始值0xF0 默认全禁用
//1-禁用下拉 0-启用下拉
#define C_PB_PLB 0xF0
#define C_PB3_PLB 0x80
#define C_PB2_PLB 0x40
#define C_PB1_PLB 0x20
#define C_PB0_PLB 0x10
(2)BPHCON 使用
//方式1:宏定义表示
BPLCON = (unsigned char)~C_PB1_PLB; //PB1下拉,其他禁用
BPHCON = (unsigned char)~(C_PB2_PLB | C_PB1_PLB); //PB21x下拉,其他禁用
//方式2:使用十六或二进制表示
BPLCON = 0B01111111; //PB3下拉
BPLCON = 0xF0; //全部禁用下拉
BPLCON = 0x00; //全部启用下拉
4.开漏输出 — BODCON
(1)BODCON 解释
//BODCON 初始值0x00 默认全禁用
//1-开启 0-禁用
#define C_PB_OD 0x3F
#define C_PB5_OD 0x20
#define C_PB4_OD 0x10
#define C_PB2_OD 0x04
#define C_PB1_OD 0x02
#define C_PB0_OD 0x01
(2)BODCON 使用
//方式1:宏定义表示
BODCON = C_PB0_OD; //设置PB0为开漏输出
BODCON = C_PB5_OD | C_PB1_OD; //设置PB51为开漏输出
//方式2:使用十六或二进制表示
BODCON = 0x3F; //PB0-5设置为开漏输出
BODCON = 0B00100010; //设置PB51为开漏输出
## 二、修改GPIO的高低电平
1.源码
typedef struct __PORTBbits_t
{
unsigned PB0 : 1;
unsigned PB1 : 1;
unsigned PB2 : 1;
unsigned PB3 : 1;
unsigned PB4 : 1;
unsigned PB5 : 1;
unsigned GP6 : 1; //!< General purpose read/write register bit
unsigned GP7 : 1; //!< General purpose read/write register bit
} __PORTBbits_t;
//! PortB (PortB Data Register)
extern __at(0x0006) __sfr PORTB;
extern __at(0x0006) volatile __PORTBbits_t PORTBbits; //!< PortB Data Register
__sbit PB0 = PORTB : 0;
__sbit PB1 = PORTB : 1;
__sbit PB2 = PORTB : 2;
__sbit PB3 = PORTB : 3;
__sbit PB4 = PORTB : 4;
__sbit PB5 = PORTB : 5;
2.使用方式
根据源码,有两种方式可以修改PB引脚的高低电平
//1.使用位变量
PB1 = 0;
PB2 = 1;
//2.使用结构体成员
PORTBbits.PB3 = 0;
PORTBbits.PB4 = 1;
三、中断
1.定时器中断
#include <ny8.h>
#include "ny8_constant.h"
/*
* 晶振频率:8MHz,时钟周期数:4T
* 该示例实现的功能:
* 每次进入中断使变量system_tick,单位毫秒
* 当system_tick达到5ms和100ms的时候,while循环执行代码
*/
#define SYSTEM_5MS 0x01
#define SYSTEM_100MS 0x02
volatile unsigned char system_tick = 0;//系统计时变量
/**
* 中断,本代码中每约5ms进入一次中断
*/
void isr() __interrupt(0)
{
static unsigned char tick_100ms = 0; //100ms计时变量
if(T0IF)//Timer0溢出中断标志
{
T0IF = 0;//清除中断标志
TMR0 = 100;//Timer0寄存器重新从100开始计数
system_tick |= SYSTEM_5MS;
//每5ms进入中断,计数20次就是100ms
if(++tick_100ms >= 20)
{
tick_100ms = 0;
system_tick |= SYSTEM_100MS;
}
}
}
/**
* 初始化定时器函数
*/
void timer_init(void)
{
DISI(); //关闭中断
PCON1 = C_TMR0_Dis; //关闭时钟
TMR0 = 100; //Timer0寄存器计数从100开始计算
T0MD = C_PS0_TMR0; //将预分频器0分配给Timer0
T0MD |= C_PS0_Div64;//预分频器64分频,时钟源为指令时钟
INTE = C_INT_TMR0; //使能Timer0溢出中断
INTF = 0; //清除所有中断标志
PCON1 = C_TMR0_En; //使能时钟
PCON = C_WDT_En | C_LVR_En; //看门狗使能,低压复位使能
ENI(); //开启中断
}
void do_something(){}
void main()
{
timer_init();//初始化定时器
while(1)
{
//系统计时5ms
if(system_tick & SYSTEM_5MS)
{
CLRWDT();//清理看门狗
system_tick &= ~SYSTEM_5MS;//清零系统计时
do_something();//执行某些任务
}
//系统计时100ms
if(system_tick & SYSTEM_100MS)
{
CLRWDT();//清理看门狗
system_tick &= ~SYSTEM_100MS;//清零系统计时
do_something();//执行某些任务
}
}
}
对于 Timer0 的时间计算,首先要知道以下4个参数:
晶振频率、时钟周期数、预分频数、计数器值
这4个参数都是可以自己设置的,如上图我设置了晶振频率4MHz,时钟周期数4T,预分频64,计数从0开始(8位单片机最大计数值为256-1=255)
接下来就是计算公式:
机器周期 T1 = 1÷(晶振频率 ÷ 时钟周期数) = 1 ÷ (4 ÷ 4) = 1 us 预分频后定时器时钟周期 T2 = T1 x 预分频数 = 1 x 64 = 64 us 计数值溢出后总的定时时间 T = 计数器值 x T2 = 255 x 64 = 16320 us = 16.32 ms 最终计算结果位16.32ms
我计算了一个比较好用的计算值,也就是前面代码的设置:
晶振频率:8MHz
时钟周期数:4T
预分频数:64
计数器值:100
定时结果:5ms(4.96ms)
四、看门狗
WDT(WatchDog Timer)看门狗
对其的通俗解释就是它是你家的二哈,你每天都要及时给它吃东西,否则你家就要被拆了
WDT 就是这么一个定时器电路,一般有个输入端(叫喂狗),一个输出到MCU的RST端(复位);每过一段时间,你需要及时的输出一个信号到输入端,给WDT清零,否则超过规定时间不喂狗,它就会发送复位信号到MCU进行复位(也就是狗把家拆了),放置MCU发生死机。
WDT 的作用就是放置程序发生死循环,或者说程序跑飞
看门狗属于定时器电路,所以就理所当然的涉及到了定时器和中断了,使能代码如下:
PCON |= C_WDT_En; //使能看门狗
PCON |= C_LVR_En; //低压复位使能
另外,定时喂狗使用的代码如下:
CLRWDT(); //清理看门狗
具体的使用在定时器中断也有使用
作者:Alysop