一·初始化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上拉

4.下拉电阻 — 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;  //全部启用下拉

5.开漏输出 — BODCON

注:

·上拉和下拉的默认状态都是全部禁用,但是具体初始值不同
·以 NY8A050D 为例,具备上拉功能的引脚有PB0-PB5,但具备下拉功能的引脚只有PB0-PB3,具体需要查看芯片文档

(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();//执行某些任务
        }
    }
}


这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)

2.PB输入变化中断

3.外部中断

四、看门狗

WDT(WatchDog Timer)看门狗

对其的通俗解释就是它是你家的二哈,你每天都要及时给它吃东西,否则你家就要被拆了

WDT 就是这么一个定时器电路,一般有个输入端(叫喂狗),一个输出到MCU的RST端(复位);每过一段时间,你需要及时的输出一个信号到输入端,给WDT清零,否则超过规定时间不喂狗,它就会发送复位信号到MCU进行复位(也就是狗把家拆了),放置MCU发生死机。

WDT 的作用就是放置程序发生死循环,或者说程序跑飞

看门狗属于定时器电路,所以就理所当然的涉及到了定时器和中断了,使能代码如下:

PCON |= C_WDT_En;    //使能看门狗
PCON |= C_LVR_En;    //低压复位使能

另外,定时喂狗使用的代码如下:
CLRWDT(); //清理看门狗

五、低功耗

1.暂停模式

SLEEP();//执行指令进入暂停模式(从正常模式)


公瑾
1 声望2 粉丝