单片机型号:STC15W4K32S4
数字编码器EC11作为控制波形、频率、占空比的开关
液晶1602A作为显示信息
单片机源程序如下:
Note:
2020-05-06 Update
1. Fix an error in main funciton, cause the EC11 Encoder rotate disorder.
2. Fix an error of interface display during switch frequency.
2020-05-24 Update
1. Fix precision of PWM frequency
2. Fix the information error in interface
波形发生器
作者:老刘爱捣鼓
版本:V0.3.1
单片机型号:STC15W4K32S4 @24MHz
B站视频教程:/zixunimg/eeworldimg/www.bilibili.com/video/BV12k4y197Qu
老刘爱捣鼓(全网同名)期待您的关注!
规格:
输出:单通道
方波:1Hz~4MHz
正弦波:1Hz-10kHz
波幅:约等于VCC,5V左右
带载能力:无带载能力
显示屏:LCD1602
控制:EC11编码器
界面:
左下角显示波形图标(方波/正弦波)和输出状态(On/OFF)
F:频率
D:方波占空比
CD:时钟分频系数(For information only)
P:用于生成正弦波的PWM频率(For information only)
Pt:用于生成正弦波的点数(For information only)
操作:
单击编码器:方波界面下,切换频率和占空比
双击编码器:开启或关闭波形输出
长按编码器:切换方波界面/正弦波界面/电压显示界面
旋转编码器:调节参数
2020-05-06 更新
1. 修正main函数循环中会引起编码器旋转混乱的错误
将main函数中while循环中的Update_Flag=0;放到前面清零,放在后面会在编码器高速旋转时,多次触发中断而Update_Flag在最后被清零则无法正确更新LCD
2. 修正在切换频率时,界面的显示错误
2020-05-24 Update
1. 修正PWM频率精度
2. 修正界面信息的显示错误
*/
#include
#include
#include "lcd1602.h"
#include "wave.h"
#include "settings.h"
#include "delay.h"
#include "config_stc.h"
//#include "uart.h"
//#include "stdio.h"
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef int8
#define int8 char
#endif
#ifndef uint16
#define uint16 unsigned int
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
#define TIMER_0 1 //定时器0中断序号
#define INT_1 2 //编码器旋转 触发外部中断
#define INT_0 0 //编码器按下 触发外部中断
uint8 Timer0_Count;
bit Update_Flag = 1;
void main(void)
{
//LCD Pin
P1M1 &= 0x00; //设置P1口为准双向
P1M0 &= 0x00; //设置P1口为准双向
P0M1 &= 0x00; //设置P0口为准双向
P0M0 &= 0x00; //设置P0口为准双向
//信号输出Pin
PWM3 = 0; //设置PWM3 P4.5低电平
PWM4 = 0; //设置PWM4 P4.4低电平
P4M1 |= 0x30; //设置P4.4(PWM4_2),4.5(PWM3_2)为高阻
P4M0 &= ~0x30; //设置P4.4(PWM4_2),4.5(PWM3_2)为高阻
/* 编码器旋转中断
Interrupt for Encoder Rotation */
IT1 = 0; //外部中断1触发方式,上升沿和下降沿
PX1 = 1; //外部中断1高优先级
EX1 = 1; //开启外部中断1
/* 编码器按键中断
Interrupt for Encoder Click */
IT0 = 1; //外部中断0触发方式,下降沿
PX0 = 1; //外部中断0高优先级
EX0 = 1; //开启外部中断0
/* 定时器0,用于更新电压信息计时
Timer 0 for updating the information of VCC*/
TMOD &= 0xF0; //设置定时器0模式 16位自动重载,在Keil中debug的话,请注意,这种设置是8051的旧13位模式
AUXR &= ~0x80; //定时器0时钟12T模式
TL0 = 0xC0; //设置定时初值 24MHz 20ms
TH0 = 0x63; //设置定时初值 24MHz 20ms
ET0 = 1; //允许T0溢出中断
/* 定时器1,用于生成小于50Hz的PWM
Timer 1 for generate the PWM when frequency less than 50Hz*/
TMOD &= 0x0F; //工作模式,0: 16位自动重装
AUXR &= ~0x40; //12T
ET1 = 1; //允许中断
EA = 1; //开总中断
//UartInit();
//UartInit_interrupt();
PWM_Hz_Pre = PWM_Hz;
Wave_Shape_Pre = Wave_Shape;
Get_PWM_Duty_Limit();
if (PWM_Duty > PWM_Max_Duty)
PWM_Duty = PWM_Max_Duty;
else if (PWM_Duty < PWM_Min_Duty)
PWM_Duty = PWM_Min_Duty;
Lcd_Init();
while (1)
{
if (Update_Flag)
{
/* Update_Flag要马上清零,如果放在Update_LCD后面,会造成假如Update_LCD的过程中再次触发编码器旋转中断的话,
在执行完Update_LCD后,在中断中置位的Update_Flag却被清零了,造成LCD没刷新,输出和显示的不一致。
另一种方法是在执行Update_LCD前把中断关掉,执行完再打开中断, 但如果这里面的函数执行时间比较长,会产生旋转触发不及时,使用感受卡顿。
关中断来避免重复触发是有好处的,可以避免在函数执行过程中多次触发将参数修改掉,
函数执行过程中参数被修改,可能会造成计算结果混乱,严重时会造成溢出,甚至单片机复位死机。 */
Update_Flag = 0;
Wave_OFF();
if (Wave_Shape_Pre != Wave_Shape)
{
Wave_Shape_Pre = Wave_Shape;
if (Wave_Shape == 0)
{
EX1 = 0; //关闭外部中断1(编码器旋转)
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时 (定时器0为VCC更新计时)
}
else if (Wave_Shape == 1)
{
PWM_Hz = PWM_Hz_Pre
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』