STC8H8K64U 学习笔记 - PWM
- 环境说明
 - 引脚说明
 
- PWM
 - 呼吸灯
 - 震动马达
 
- 乐谱
 
环境说明
该内容仅针对我自己学习的开发板做的笔记,在实际开发中需要针对目标电路板的原理图进行针对性研究。
- 芯片:STC8H8K64U
 - 烧录软件:stc-isp-v6.92G
 - 编码工具:天问
 
引脚说明
P0_0:蜂鸣器,按频率发音,1:高,0:低P0_1:电动马达,0:停,1:动P5_3:小蓝灯,0:灭,1:亮P2_7:1 号 LED 灯,0:亮,1:灭P2_6:2 号 LED 灯,0:亮,1:灭P1_5:3 号 LED 灯,0:亮,1:灭P1_4:4 号 LED 灯,0:亮,1:灭P2_3:5 号 LED 灯,0:亮,1:灭P2_2:6 号 LED 灯,0:亮,1:灭P2_1:7 号 LED 灯,0:亮,1:灭P2_0:8 号 LED 灯,0:亮,1:灭P5_1:1 号按键,0:按下,1:弹起P5_2:2 号按键,0:按下,1:弹起P5_3:3 号按键,0:按下,1:弹起P5_4:4 号按键,0:按下,1:弹起P3_4:矩阵键盘第 1 行引脚P3_5:矩阵键盘第 2 行引脚P4_0:矩阵键盘第 3 行引脚P4_1:矩阵键盘第 4 行引脚P0_3:矩阵键盘第 1 列引脚P0_6:矩阵键盘第 2 列引脚P0_7:矩阵键盘第 3 列引脚P1_7:矩阵键盘第 4 列引脚
PWM
- 频率和周期的关系 
  
- 频率(Frequency): 表示单位时间内发生事件的次数。常用单位是赫兹(Hz),1赫兹等于每秒一个周期。
 - 周期(Period): 表示一个完整事件发生所需的时间。周期是频率的倒数。
 - 举例: 
    
- 24MHz(兆赫兹),每秒计算24M次,1M = 1k * 1k = 1 000 000 
      
- 那么周期的时间就是
1/24MHz=41.67ns,那么计算1次需要41.67ns,就是说执行1次所需的时间 
 - 那么周期的时间就是
 
 - 24MHz(兆赫兹),每秒计算24M次,1M = 1k * 1k = 1 000 000 
      
 
 - PWM全称是脉宽调制(Pulse Width Modulation),是一种通过改变信号的脉冲宽度来控制电路输出的技术。
 - PWM与引脚对应关系(引脚来源:《stc8h.pdf》的 997 页)
 

呼吸灯
通过 PWM 设置 LED 灯的亮度
#define PWM_DUTY_MAX 1000//PWM最大占空比值
#include <STC8HX.h>
uint32 sys_clk = 24000000;//设置PWM、定时器、串口、EEPROM频率参数
#include "lib/twen_board.h"
#include "lib/PWM.h"
#include "lib/delay.h"
uint16 index = 0;
int16 inc = 5;
uint16 frequency = 1000;
void setup() {
  twen_board_init();//天问51初始化
  
  pwm_init(PWM4N_P27, frequency, 0);
  pwm_init(PWM4P_P26, frequency, 0);
  // pwm_init(PWM3N_P15, frequency, 0);
  // pwm_init(PWM3P_P14, frequency, 0);
  // pwm_init(PWM2N_P23, frequency, 0);
  // pwm_init(PWM2P_P22, frequency, 0);
  // pwm_init(PWM1N_P21, frequency, 0);
  // pwm_init(PWM1P_P20, frequency, 0);
}
void loop() {
  pwm_duty(PWM4N_P27, index);
  pwm_duty(PWM4P_P26, index);
  // pwm_duty(PWM3N_P15, index);
  // pwm_duty(PWM3P_P14, index);
  // pwm_duty(PWM2N_P23, index);
  // pwm_duty(PWM2P_P22, index);
  // pwm_duty(PWM1N_P21, index);
  // pwm_duty(PWM1P_P20, index);
  
  delay(1);
  if(index >= 1000) {
    inc = -5;
  }
  if(index <= 0) {
    inc = 5;
  }
  index+= inc;
}
void main(void) {
  setup();
  while(1){
    loop();
  }
}
 
震动马达
通过 PWM 设置马达的震动强度
#define PWM_DUTY_MAX 1000//PWM最大占空比值
#include <STC8HX.h>
uint32 sys_clk = 24000000;//设置PWM、定时器、串口、EEPROM频率参数
#include "lib/twen_board.h"
#include "lib/PWM.h"
#include "lib/delay.h"
uint16 index = 0;
int16 inc = 5;
uint16 frequency = 1000;
void setup() {
  twen_board_init();//天问51初始化
  
  pwm_init(PWM6_P01, frequency, 0);
  P0M1&=~0x02;P0M0|=0x02;//推挽输出
}
void loop() {  
  pwm_duty(PWM6_P01, index);
  
  delay(1);
  if(index >= 1000) {
    inc = -5;
  }
  if(index <= 0) {
    inc = 5;
  }
  index+= inc;
}
void main(void) {
  setup();
  while(1){
    loop();
  }
}
 
乐谱
#define PWM_DUTY_MAX 1000//PWM最大占空比值
#include <STC8HX.h>
uint32 sys_clk = 24000000;//设置PWM、定时器、串口、EEPROM频率参数
#include "lib/twen_board.h"
#include "lib/UART.h"
#include "lib/PWM.h"
// 哆Do  来Re  咪Mi  发Fa  唆So  拉La  西Si  哆Do
// 523,  587,  659,  698,  784,  880,  988,  1047
// 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093
// 2093, 2349, 2637, 2794, 3135, 3520, 3951, 4186
// 设定小字2组的音阶
#define s2_Do 1047
#define s2_Re 1175
#define s2_Mi 1319
#define s2_Fa 1397
#define s2_So 1568
#define s2_La 1760
#define s2_Si 1976
// 设定小字3组的音阶
#define s3_Do 2093
#define s3_Re 2349
#define s3_Mi 2637
#define s3_Fa 2794
#define s3_So 3135
#define s3_La 3520
#define s3_Si 3951
#define s4_Do 4186
// 设定默认的中音(小字2组的音阶)
#define M1 1047
#define M2 1175
#define M3 1319
#define M4 1397
#define M5 1568
#define M6 1760
#define M7 1976
// 设定默认的高音(小字3组的音阶)
#define G1 2093
#define G2 2349
#define G3 2637
#define G4 2794
#define G5 3135
#define G6 3520
#define G7 3951
void putchar(char c) {
  if (c == '\n') {
    uart_putchar(UART_1, 0x0d);
    uart_putchar(UART_1, 0x0a);
  } else {
    uart_putchar(UART_1, (uint8)c);
  }
}
// 每个音阶之间的停顿时间
uint16 spot = 200;
// 单个音阶的持续时间
uint16 duration = 100;
// 按键按下标志位
uint8 pressed1 = 0;
uint8 pressed2 = 0;
// 连续播放乐谱数组过程中的循环索引值
uint16 index = 0;
// 连续播放乐谱数组过程中的循环长度
uint16 lenth = 0;
void setup() {
  twen_board_init();//天问51初始化
  P0M1&=~0x01;P0M0|=0x01;//推挽输出
  uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 115200, TIM_1);//初始化串口
}
// 启动蜂鸣器(输入单位 hz)
// @param hz        蜂鸣器输入频率
// @param recess    与下一个音阶之间的休息时间
void launchBuzzer(const uint16 hz, uint16 recess) {
  // 假设入参是 523 Hz, 即  523 次/秒
  // 换算为 1000ms 执行 523 次
  // 得到每次执行的时间是 1000ms / 523 次 ≈ 1.912 ms
  // 高低电平各占一半, 即约等于 0.956 ms
  
  // duration = 1000 / hz / 2;
  // printf_small("duration is %d\n", duration);
  // P0_0 = 1;
  // delay(duration);
  // P0_0 = 0;
  // delay(duration);
  
  if(hz == 0) {
    // 如果传入是 0 表示该音阶置空
    delay(duration);
    return;
  }
  pwm_init(PWM5_P00, hz, 500);
  delay(duration);
  pwm_duty(PWM5_P00, 0);
  if(recess > 0) {
    delay(recess);
  }
}
// 乐谱 —— 生日快乐
xdata uint16 music_score_birthday[] = {
  G5, G5, G6, G5, M1, G7,
  G5, G5, G6, G5, M2, M1,
  G5, G5, M5, M3, M1, G7, G6,
  M4, M4, M3, M1, M2, M1
};
// 乐谱 —— 哆啦A梦
xdata uint16 music_score_doraemon[] = {
  G5,M1,M1,M3,  M6,M3,M5,
  M5,M6,M5,M3,  M4,M3,M2,
  M6,M2,M2,M4,  M7,M7,M6,M5,
  M4,M4,M3,  M6,M7,M1,M2,
  
  G5,M1,M1,M3,  M6,M3,M5,
  M5,M6,M5,M3,  M4,M3,M2,
  M6,M2,M2,M4,  M7,M6,M5,
  M4,M4,M3,M2,  M7,M2,M1
};
// 播放指定乐谱
void play(uint16 *ps, uint16 len) {
  for(index = 0; index < len; index++) {
    launchBuzzer(ps[index], spot);
  }
  delay(1000);
}
void loop() {
  // 按下按键 1 播放 生日快乐
  if(P5_1 == 0 && pressed1 == 0) {
    pressed1 = 1;
    lenth = sizeof(music_score_birthday) / sizeof(uint16);
    play(music_score_birthday, lenth);
  } else if(P5_1 == 1 && pressed1 == 1) {
    pressed1 = 0;
  }
  
  // 按下按键 2 播放 哆啦A梦
  if(P5_2 == 0 && pressed2 == 0) {
    pressed2 = 1;
    lenth = sizeof(music_score_doraemon) / sizeof(uint16);
    play(music_score_doraemon, lenth);
  } else if(P5_2 == 1 && pressed2 == 1) {
    pressed2 = 0;
  }
}
void main(void) {
  setup();
  while(1){
    loop();
  }
}
 
有部分音阶不太对,可能是频率值弄错了,但影响不大!



















