8/16 位PPG 是一个8 位重载定时器模块,它通过对脉冲输出的控制来形成PPG 输出。8/16 位PPG 也可以用两个8 位模块来构建16 位定时器。
7.3.1 8/16bit PPG 原理及应用
8/16 位PPG 的工作模式包括了:双8 位PPG,8 位预分频PPG,16 位PPG。
8/16 位PPG 中断说明

![]()
7.3.2 8/16bit PPG 寄存器设置及I/O 端口选择
8/16 位PPG 端口引脚:PPG00 和PPG01。两者在前面介绍引脚时提到既可以作为8-16 位PPG 专用输出口也可以当作普通得I/O 口使用,主要由专用寄存器位PC0:POEN0 和PC1:POEN1 来控制。
要控制8/16 位PPG 的工作模式,则首先要对其寄存器进行了解。8/16 位PPG 的控制寄存器包括:PPG 控制寄存器0/1(PC0/1),PPG 周期设置寄存器0/1(PPS0/1),PPG 占空比设置寄存器0/1(PDS0/1),PPG 初始设置寄存器(PPGS),PPG 输出取反寄存器(REVC)
PPG 控制寄存器0/1(PC0/1),两个寄存器均能控制定时器时钟周期,输出使能,终端使能,中断标志位读写。此外,PC0 还可以设置前面介绍的PPG 的3 种工作模式。
PPG 周期设置寄存器0/1(PPS0/1)设置PPG0/1 的周期,在16 位PPG 工作模式下,PPS0 为低8 位周期设置。
PPG 占空比设置寄存器0/1(PDS0/1)设置PPG0/1 的占空比,在16 位PPG 工作模式下,PDS0 为低8 位占空比的设置。
PPG 初始设置寄存器(PPGS)设置PPG0~3 的各个管道的运行使能。
PPG 输出取反寄存器(REVC)设置PPG 各个通道的输出值是否取反。
7.3.3 8/16bit PPG 应用设计范例
这里通过一个小程序来说明:双8 位独立PPG 和8 位预分频PPG 的具体区别。程序说明让8/16 位PPG 以8 位预分频模式工作同时输出双通道,代码如下:
#include "mb95100.h"
/*****************************************************************************/
/*主程序部分*/
/*****************************************************************************/
void main(void) {
PDR2 = 0x00; // Port 2:
DDR2 = 0xff; //
PPS00 = 0x0A; // 设置0 管道的周期(10 edges of prescaler)
PDS00 = 0x03; // 设置0 管道的占空比(3 edges of prescaler)
PC00 = 0x68; // 8 位预分频模式,中断不使能,使能PPG 输出
// 初始化8 位通道1 作为通道0 的预分频
PPS01 = 0x80; // 设置1 管道的周期set period value for channel 1
PDS01 = 0x40; //设置1 管道的占空比(always 50 % needed in prescaler mode)
PC01 = 0x28; // 中断不使能,使能PPG 输出
PPGS = 0x03; // PPG 0 和1 管道输出运行
}
当上面的代码中PC00 = 0x28 ,其他保持不变时,则程序变为以双8 位独立模式工作同时输出双通道,然后通过示波器对比两次的输出波形及频率。读者可以发现两次的输出波形完全一样。这是因为无论是8+8 预分频还是双8 位独立PPG 工作模式下,由于设置的占空比完全一样,所以输出波形也完全一样。而测试频率就可以发现,两次模式下PPG1 的频率是相同的,而PPG0 不同。这是因为两种模式均不影响PPG1 的频率输出,而在程序设置中由于周期和占空比均设置一致,故频率一样。而在8+8 预分频模式下PPG0 的频率主要由PPG1 作为时钟预分频来影响,双8 位独立PPG 工作模式下两个定时器的频率是完全独立的,所以两种模式下PPG0 的频率完全不同。由于可以利用PPG1 作为时钟预分频因此在对PPG0 的频率设置中,几乎可以设置任何频率,这是其他定时器/计时器所无法完成的。
代码说明:通过中断控制多种PPG 模式之间的切换的。
#include "mb95100.h"
#define SEG_A 0x01
#define SEG_B 0x02
#define SEG_C 0x04
#define SEG_D 0x08
#define SEG_E 0x10
#define SEG_F 0x20
#define SEG_G 0x40
#define SEG_DP 0x80
#define SEG_0 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F
#define SEG_1 SEG_B | SEG_C
#define SEG_2 SEG_A | SEG_B | SEG_D | SEG_E | SEG_G
#define SEG_3 SEG_A | SEG_B | SEG_C | SEG_D | SEG_G
#define SEG_4 SEG_B | SEG_C | SEG_F | SEG_G
#define SEG_5 SEG_A | SEG_C | SEG_D | SEG_F | SEG_G
#define SEG_6 SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G
#define SEG_7 SEG_A | SEG_B | SEG_C
#define SEG_8 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G
#define SEG_9 SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G
const unsigned char seg_display[12] = { SEG_0, SEG_1, SEG_2, SEG_3, SEG_4,
SEG_5, SEG_6, SEG_7, SEG_8, SEG_9, 0xff, 0x00 };
//LED 初始化
unsigned char flag_16PPG;
unsigned char flag_8PPG;
unsigned char flag_16PPG_mode;
unsigned char flag_8PPG_mode;
/*****************************************************************************/
/* Main Routine */
/*****************************************************************************/
void main(void) {
PDR0 = 0xff; // Port 0:
DDR0 = 0xff; // 7 段显示
PDR1 = 0x00; // Port 1:
DDR1 = 0xff ;
PUL1 = 0xff;
PDR2 = 0x00; // Port 2:
DDR2 = 0x03; /*8-16 位PPG 通道ch0 输出 :8bit PPG 输出*/
PDR3 = 0x00; // Port 3:
AIDRL = 0xff;
DDR3 = 0xff;
PDR4 = 0x00; // Port 4:
AIDRH = 0xff;
DDR4 = 0xff;
PDR5 = 0x00; // Port 5:
DDR5 = 0xff;
PDR6 = 0xff; // Port 6:
DDR6 = 0x01; /*8-16bit PPG 通道 ch1 输出:16bit PPG 输出*/
PDR7 = 0x00; // Port 7:
DDR7 = 0xff;
PDR8 = 0x00; // Port 8:
DDR8 = 0xff;
PDRE = 0x00; // Port E:
DDRE = 0xfc; // PE0=INT10, PE1=INT11 键位输入外部中断;
//端口设置
flag_16PPG = 0x00; /*计数标志位*/
flag_8PPG = 0x00; /*计数标志位*/
flag_16PPG_mode = 0x00; /* 模式标志位*/
flag_8PPG_mode = 0x00; /*模式标志位*/
// __EI();
// 功能开始,中断设置
InitIrqLevels(); // allow all levels
__EI(); // globaly enable interrupts
__set_il(3); // set global interrupt mask to allow all IRQ levels
/*8-16bit PPG 初始化*/
/*PPG ch0: 双8 位PPG 独立模式 */
PC01 = 0x28; /* 中断使能, 1/MCLK count */
PC00 = 0x28; /* 中断使能, 1/MCLK count*/
PPS01 = 0xFF; /*PPG period = 0xFF*/
PPS00 = 0x7F; /*PPG period = 0x7F*/
PDS01 = 0x7F; /* Duty 50% (0xFF/2=0x7F) */
PDS00 = 0x3F; /* Duty 50% (0x7F/2=0x3F) */
REVC = 0x02; /* ch0-Upper unit output reverce level*/
/*PPG ch1:16bit PPG mode <->8bit PPG + 8bit pre-scaler mode */
/*初始化16 位PPG 模式*/
PC11 = 0x00; /* 中断,输出全关断 */
PC10 = 0xA8; /* 中断使能, 1/MCLK count*/
PPS11 = 0x01; /*PPG period = 0x01FF*/
PPS10 = 0xFF;
PDS11 = 0x01; /* Duty 75% (0x01FF/4*3=0x017F) */
PDS10 = 0x7F;
/* PPG start */
PPGS = 0x07;
while(1)
{
__wait_nop();
__wait_nop();
__wait_nop();
__wait_nop();
__wait_nop();
}
}
/*****************************************************************************/
/*中断 */
/*****************************************************************************/
/* PPG 中断处理*/
__interrupt void PPG_ch1_L_int(void)
{
__DI();
flag_16PPG ++;
if (flag_16PPG_mode == 0){
if (flag_16PPG > 0x7F)
{ /* duty change */
PPGS_PEN10 = 0; /*16bit PPG stop*/
PDS11 = 0x00; /* Duty 25% (0x01FF/4=0x7F) */
PDS10 = 0x7F;
flag_16PPG = 0;
flag_16PPG_mode = 1;
}
} // 当条件触发,16 位PPG 的占空比设置为25%
else {
if (flag_16PPG > 0x7F)
{ /* duty change */
PPGS_PEN10 = 0; /*16bit PPG stop*/
PDS11 = 0x01; /* Duty 75% (0x01FF/4*=0x7F) */
PDS10 = 0x7F;
flag_16PPG = 0;
flag_16PPG_mode = 0;
}
}
PC10_P UF0 = 0; /*count borrow bit clear*/
PPGS_PEN10 = 1; /*16bit PPG start*/
__EI();
} // 当条件触发,16 位PPG 的占空比设置为75%
__interrupt void PPG_ch1_U_int(void)
{
/*PPG_ch1 is "16bit PPG mode", so this handler is not used.*/
}
__interrupt void PPG_ch0_U_int(void)
{
__DI();
flag_8PPG += 1;
if (flag_8PPG_mode == 0){
if (flag_8PPG > 0x7F)
{ /* mode change */
PPGS_PEN00 = 0; /*8 位PPG 停止*/
PPGS_PEN01 = 0; /*8 位PPG 停止*/
PC01 = 0x28; /* 中断使能, 1/MCLK 计数*/
PC00 = 0x68; /*8 位预分频计数模式 */
PPS01 = 0x0A; /*PPG period = 0x0A*/
PPS00 = 0x0A; /*PPG period = 0x0A*/
PDS01 = 0x05; /* Duty 50% (0x0A/2=0x05) */
PDS00 = 0x05; /* Duty 50% (0x0A/2=0x05) */
flag_8PPG = 0;
flag_8PPG_mode = 1;
PC01_PUF1 = 0; /* 计数器借位标志位清零*/
PC00_PUF0 = 0; /* 计数器借位标志位清零*/
PPGS_PEN00 = 1; /*8 位PPG 开始*/
PPGS_PEN01 = 1; /*8 位PPG 开始*/
} // 触发条件产生,双8 位PPG 转变为预分频工作模式
else
{
PC01_PUF1 = 0; /* 计数器借位标志位清零*/
PC00_PUF0 = 0; /* 计数器借位标志位清零*/
}
}
else {
if (flag_8PPG > 0x7F)
{ /* mode change */
PPGS_PEN00 = 0; /*8bit PPG stop*/
PPGS_PEN01 = 0; /*8bit PPG stop*/
PC01 = 0x28; /*interrput enable, 1/MCLK count*/
PC00 = 0x28; /*8bit PPG x2ch mode*/
PPS01 = 0xFF; /*PPG period = 0xFF*/
PPS00 = 0x7F; /*PPG period = 0x7F*/
PDS01 = 0x7F; /* Duty 50% (0xFF/2=0x7F) */
PDS00 = 0x3F; /* Duty 50% (0x7F/2=0x3F) */
flag_8PPG = 0;
flag_8PPG_mode = 0;
PC01_PUF1 = 0; /*count borrow bit clear*/
PC00_PUF0 = 0; /*count borrow bit clear*/
PPGS_PEN00 = 1; /*8bit PPG start*/
PPGS_PEN01 = 1; /*8bit PPG start*/
}
//触发条件产生,预分频PPG 转变为双8 位工作模式,具体代码和前面的功能一样
else
{
PC01_PUF1 = 0; /*count borrow bit clear*/
PC00_PUF0 = 0; /*count borrow bit clear*/
}
}
__EI();
}
__interrupt void PPG_ch0_L_int(void)
{
__DI();
PC00_PUF0 = 0; /*count borrow bit clear*/
__EI();
}


