-
计时中断开不起来:
需要开启定时器, 开启总中断控制
ET0 = 1;
EA = 1; -
PWM 端口指定, 按示例无法使用其他端口
更改输出端口需要修改 PWMA_CCER1, PWMA_ENO, 文档描述看的不是太明白 -
ADC 使用时需要配置端口状态, 还有上拉电阻, 另外实际使用时跳动非常大
尝试了很多方法:
a. VCC 使用更好的电源/电池
b. Ref用的TL431去掉
c. VCC/Ref 加大电容
d. 检测信号直接用电池
e. 修改ADC速度, 读取周期等参数
这些方法都没有效果, 最后发现修改 RESFMT 解决问题
ADCCFG中的RESFMT使用0时, 买的STC8H1K08-SSOP20 有问题,跳动非常大, RESFMT使用1时正常 -
读取8位以上寄存器同步问题
如一个32位变量在定时中断中自加, 外部访问时发生错位问题, 解决方法:
a. 使用类似总线中的busy标记
b. 读取前后开关系统中断
c. 读取两次,然后比较数据校正, 等还有其他比较多方法 -
按键或其他输入消抖或等其他, 以及输入时间检测都需要计时, 有个计时系统是很有必要的
按键使用计数判断点击, LED输出用计数保持状态 -
旋转编码器检测的间隔用1-4ms, 太长就会出现误报情况
-
数码管每个总循环显示一个字符, 这样效果会更好(内部储存需要显示的全数据)
#include <intrins.h>
#include "STC/stc8h.h"
#include "../Common/inttype.h"
#define S2P_DAT P3^2 //串行数据输入
#define S2P_SHIFT P3^4 //移位――上升沿有效
#define S2P_STORE P3^3 //储存――上升沿有效
#include "../Common/Dcd595.c"
#define MAIN_Fosc 24000000L //定义主时钟
#define PIN_RotA P12
#define PIN_RotB P13
#define PIN_RotK P14
#define PIN_LED1 P15
#define PIN_LED2 P16
#define PIN_LED3 P17
#define PIN_SW P54
#define PIN_ADC1 P35
#define PIN_ADC2 P36
#define PIN_DDS P37
#define PIN_PWM1 P11
#define PIN_PWM2 P10
#define SW_TM1 5
#define SW_TM2 500
#define STEP1 10
#define STEP2 1
#define LED_tm 20
#define LED_tmf 100
static ulong SYS_time = 0; // us
static uchar SYS_time_busy = 0;
static int16 pwm_d = 150;
static int16 pwm_max = 500;
static int8 pwm_step = STEP1;
uchar in_sw;
uchar in_rot_sw;
uchar in_rot;
uchar out_led1 = LED_tmf;
uchar out_led2 = 0;
uchar out_led3 = 0;
#define FUN_Max 2
int8 fun_id = 0; // 0:ADC_PWM 1:ADC_VCC 2:PWM 3:DDS 4:
uchar dcd_dirt = 0;
u32 dcd_out = 0;
uchar GetExout()
{
uchar v;
v = 0x80 >> fun_id;
return v;
}
void SetDcd(u32 value)
{
dcd_dirt = 1;
if(value != -1)
dcd_out = value;
}
void Timer0_Isr(void) interrupt 1
{
static uchar SYS_time_skip = 0;
uchar cts;
if(SYS_time_busy)
{
SYS_time_skip ++;
return;
}
cts = 1 + SYS_time_skip;
SYS_time_skip = 0;
SYS_time += cts;
return;
}
#define Timer0_Reload (65536UL -(MAIN_Fosc / 10000))
void Timer0_Init(void) //100微秒@24MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //需要开启定时器, 开启中断
EA = 1;
}
/*
VAL 1K28 1K08 3K64 4K64 8K64 1/2K08U/T
0000 ADC0 P1.0 P1.0 P1.0 P1.0 P1.0 P1.0
0001 ADC1 P1.1 P1.1 P1.1 P1.1 P1.1 P1.1
0010 ADC2 P1.2 没有 P1.2 P5.4 P5.4 P5.4
0011 ADC3 P1.3 没有 没有 P1.3 P1.3 P1.3
0100 ADC4 P1.4 没有 没有 P1.4 P1.4 P1.4
0101 ADC5 P1.5 没有 没有 P1.5 P1.5 P1.5
0110 ADC6 P1.6 没有 P1.6 P1.6 P6.2 P1.6
0111 ADC7 P1.7 没有 P1.7 P1.7 P6.3 P1.7
1000 ADC8 P0.0 P3.0 P0.0 P0.0 P0.0 P3.0
1001 ADC9 P0.1 P3.1 P0.1 P0.1 P0.1 P3.1
1010 ADC10 P0.2 P3.2 P0.2 P0.2 P0.2 P3.2
1011 ADC11 P0.3 P3.3 P0.3 P0.3 P0.3 P3.3
1100 ADC12 没有 P3.4 P0.4 P0.4 P0.4 P3.4
1101 ADC13 没有 P3.5 P0.5 P0.5 P0.5 P3.5
1110 ADC14 没有 P3.6 P0.6 P0.6 P0.6 P3.6
1111 1.19V _有_ _有_ _有_ _有_ _有_ _有_
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
====== ===== ======= =========== ==============
ADCTIM FEA8H CSSETUP CSHOLD[1:0] SMPDUTY[4:0]
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
====== ===== ===== ===== ====== === ==============
ADCCFG DEH - - RESFMT - SPEED[3:0]
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
========= ===== ========= ========= ======== ======== ==============
ADC_CONTR BCH ADC_POWER ADC_START ADC_FLAG ADC_EPWMT ADC_CHS[3:0]
ADCCFG中的RESFMT使用0时, 买的STC8H1K08-SSOP20 有问题,跳动非常大, RESFMT使用1时正常
*/
void Adc_Init()
{
ADCTIM = 0x3F; // 设置ADC 内部时序
ADCCFG = 0x2f; // 设置ADC 时钟为系统时钟/2/16
ADC_CONTR = 0x8F; // 使能ADC 模块
}
u16 AdcRead(uchar chl)
{
uchar h, l;
u16 val;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | chl; //启动 AD 转换
NOP4();
while((ADC_CONTR & 0x20) == 0) ; //wait for ADC finish
ADC_CONTR &= ~0x20; // 清除ADC结束标志
h = ADC_RES; // 读取ADC 结果
l = ADC_RESL;
val = ((u16)h << 8) | l;
return val;
}
static u16 ADC_read1 = 0;
static u16 ADC_read2 = 0;
void FunAdcRead()
{
u32 val;
u16 dat;
if(fun_id == 0)
{
dat = AdcRead(0x0E); //P36
ADC_read1 = dat;
val = dat;
val = val * 250 / 1024;
SetDcd(val);
}
else if(fun_id == 1)
{
dat = AdcRead(0x0D); //P35
ADC_read2 = dat;
val = dat;
// val = val * 503 / 33 * 250 / 1024;
val = val * 511 / 33 * 250 / 1024; // 补偿
SetDcd(val);
}
}
u16 GetPwmCCR()
{
return pwm_d;
}
/*
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
PWMA_CCMR1 FEC8H OC1CE OC1M[2:0] OC1PE OC1FE CC1S[1:0]
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
PWMA_CCER1 FECCH CC2NP CC2NE CC2P CC2E CC1NP CC1NE CC1P CC1E
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
PWMA_ENO FEB1H ENO4N ENO4P ENO3N ENO3P ENO2N ENO2P ENO1N ENO1P
*/
void Pwm_Init()
{
PWMA_CCER1 = 0x00; // 写CCMRx 前必须先清零CCERx 关闭通道
PWMA_CCMR1 = 0x60; // 捕获/比较模式寄存器
PWMA_CCER1 = 0x05; // 捕获/比较输出使能
PWMA_CCR1 = GetPwmCCR(); // 设置占空比时间
PWMA_ARR = pwm_max; // 设置周期时间
PWMA_ENO = 0x02; // 端口输出
PWMA_BKR = 0x80; // 使能主输出
PWMA_CR1 = 0x01; // 开始计时
// 更改输出端口需要修改 PWMA_CCER1, PWMA_ENO
}
void InitIo()
{
P_SW2 |= 0x80; // 使能访问XFR
P1M0 = 0x00;
P1M1 = 0x00;
P1PU = 0xff;
P3M0 = 0x00; P3M1 = 0x60; // 双向 ADC高阻:P35 P36
P3PU = 0x9f; // 上拉
P5PU |= 0x10;
Timer0_Init();
Adc_Init();
Pwm_Init();
ET0 = 1;
EA = 1;
return;
}
ulong GetTimeUs()
{
ulong v;
SYS_time_busy = 1;
v = SYS_time * 100; //100微秒
SYS_time_busy = 0;
return v;
}
ulong GetTimeMs()
{
ulong v;
SYS_time_busy = 1;
v = SYS_time / 10; //100微秒
SYS_time_busy = 0;
return v;
}
ulong GetTimeTick() //100微秒
{
ulong v;
SYS_time_busy = 1;
v = SYS_time;
SYS_time_busy = 0;
return v;
}
ushort Timer0_Read()
{
uchar h1, h2, l;
ushort v;
h1 = TH0;
l = TL0;
h2 = TH0;
if(h1 == h2)
v = (h1 << 8) | l;
else
v = (h2 << 8) | 0;
return v;
}
uchar CreatePwm(int d, int m)
{
static int pwm_low = 0;
static int pwm_hi = 0;
int el, eh, ov;
long sa, sb;
el = m-d;
eh = d;
sa = (long)pwm_low*eh;
sb = (long)pwm_hi*el;
if(sa >= sb)
{
ov = 1;
pwm_hi ++;
}
else
{
ov = 0;
pwm_low ++;
}
if(pwm_hi+pwm_low >= m)
{
pwm_hi = 0;
pwm_low = 0;
}
return ov;
}
uchar SwCheck(uchar a, uchar id)
{
static uint ct_en[8] = {0};
uchar v;
if(a == 0)
{
ct_en[id] ++;
return 0;
}
if(ct_en[id] > SW_TM2)
v = 2;
else if(ct_en[id] > SW_TM1)
v = 1;
else
v = 0;
ct_en[id] = 0;
return v;
}
uchar RotDec(uchar a, uchar b)
{
static uchar al = 0;
static uchar bl = 0;
uchar v;
if((a|b) != 0)
v = 0;
else if((al^bl) != 1)
v = 0;
else if(al == 0)
v = 1;
else if(bl == 0)
v = 2;
else
v = 'e';
al = a;
bl = b;
return v;
}
uchar SetLedTm(uchar *tm)
{
if(*tm == 0)
return 1;
if(*tm >= LED_tmf)
return 0;
*tm = *tm -1;
return 0;
}
void GetInput()
{
in_sw = SwCheck(PIN_SW, 1);
in_rot_sw = SwCheck(PIN_RotK, 2);
in_rot = RotDec(PIN_RotA, PIN_RotB);
if(in_sw == 1)
{
out_led3 = LED_tm;
fun_id ++;
if(fun_id > FUN_Max)
fun_id = 0;
SetDcd(-1);
}
if(in_sw == 2)
{
out_led2 = LED_tm;
out_led3 = LED_tm;
fun_id = 0;
}
if(in_rot_sw)
{
if(pwm_step != STEP1)
{
pwm_step = STEP1;
out_led1 = LED_tmf;
}
else
{
pwm_step = STEP2;
out_led1 = 0;
}
out_led3 = LED_tm;
}
if(in_rot)
{
switch(in_rot)
{
case 1: pwm_d -= pwm_step; out_led2 = LED_tm; break;
case 2: pwm_d += pwm_step; out_led3 = LED_tm; break;
}
if(pwm_d < 0)
pwm_d = 0;
if(pwm_d > pwm_max)
pwm_d = pwm_max;
if(fun_id == 0 || fun_id == 2)
{
PWMA_CCR1 = GetPwmCCR();
SetDcd(-1);
}
}
PIN_LED1 = SetLedTm(&out_led1);
PIN_LED2 = SetLedTm(&out_led2);
PIN_LED3 = SetLedTm(&out_led3);
return;
}
void FunRun()
{
uchar v;
if(dcd_dirt && fun_id == 2)
{
SetDcd(100L * pwm_d);
}
if(dcd_dirt)
{
dcd_dirt = 0;
v = GetExout();
DcdSetNum3_00(dcd_out, v);
}
}
int TimeCheck(uint *last, uint cur, uint ivt)
{
uint pass;
pass = cur - *last;
if(pass < ivt)
return 0;
*last = cur;
return 1;
}
void main()
{
uchar v, n;
uint sh, sl;
uint tm, tm_input, tm_adc;
InitIo();
v = GetExout();
DcdSetNum3_00(888, v);
tm_input = 0;
tm_adc = 0;
sh = 0;
sl = 0;
for(n=0; ; n++)
{
if(n >= 100)
n = 0;
tm = GetTimeTick();
if(TimeCheck(&tm_input, tm, 10*1))
GetInput();
if(TimeCheck(&tm_adc, tm, 10*200))
FunAdcRead();
FunRun();
DcdUpdate();
}
}
/*
#define S2P_DAT P1^0 //串行数据输入
#define S2P_SHIFT P1^1 //移位――上升沿有效
#define S2P_STORE P1^2 //储存――上升沿有效
*/
sbit HC595_SHCP = S2P_SHIFT; // 11 SHIFT
sbit HC595_STCP = S2P_STORE; // 12 STORE
sbit HC595_DAT = S2P_DAT; // 14 DATA
/*
=====A=====
|| ||
F| |B
|| ||
=====G=====
|| ||
E| |C
|| ||
=====D=====
8 4 2 1 8 4 2 1
=============== =============
DP G F E D C B A
0 0 0 1 1 1 1 1 1 0x3F
1 1 1 0x06
2 1 1 1 1 1 0x5B
3 1 1 1 1 1 0x4F
4 0x66
5 0x6D
6 0x7D
7 0x07
8 0x7F
9 0x6F
A 0 1 1 1 0 1 1 1 0x77
B 0x7C
C 0x39
D 0x5E
E 0x79
F 0x71
*/
u8 code DcdNum2Dat[] =
{
0x3F, 0x06, 0x5B, 0x4F,
0x66, 0x6D, 0x7D, 0x07,
0x7F, 0x6F, 0x77, 0x7C,
0x39, 0x5E, 0x79, 0x71
};
#define DCD_NUM0 0x3F
#define DCD_NUM9 0x6F
#define DCD_DOT 0x80
void Dcd595Init()
{
HC595_DAT = 0;
HC595_SHCP = 0;
HC595_STCP = 0;
}
void Write595(u8 val)
{
u8 i, dat;
dat = val;
HC595_SHCP = 0;
for(i=0;i<8;i++)
{
HC595_DAT = dat & 0x80;
HC595_SHCP = 1;
dat = dat << 1;
HC595_SHCP = 0;
}
}
void DcdScan(uchar seg, uchar val)
{
HC595_STCP = 0;
Write595(seg);
Write595(val);
HC595_STCP = 1;
}
static u8 Dcd_dat[8] = {0x00};
static u8 Dcd_count = 0;
static u8 Dcd_uct = 0;
static u8 Dcd_exout = 0;
void DcdSetNum3(u16 num, u8 exout)
{
u8 v0, v1, v2;
u16 value;
value = num;
v2 = value % 10; value /= 10;
Dcd_dat[2] = DcdNum2Dat[v2];
v1 = value % 10; value /= 10;
Dcd_dat[1] = DcdNum2Dat[v1];
v0 = value % 10; value /= 10;
Dcd_dat[0] = DcdNum2Dat[v0];
if(Dcd_dat[0] == DCD_NUM0)
{
Dcd_dat[0] = 0;
if(Dcd_dat[1] == DCD_NUM0)
Dcd_dat[1] = 0;
}
Dcd_count = 3;
Dcd_exout = exout;
}
// 123456 999.
// 12345 123.
// 1234 12.3
// 251 2.51
// 12 0.12
// 7 0.07
void DcdSetNum3_00(u32 num, u8 exout)
{
u16 r, d, value;
uchar v1, v2, v3, v4, v5;
Dcd_count = 3;
Dcd_exout = exout;
r = num / 100;
d = num % 100;
if(r >= 999)
{
Dcd_dat[0] = DCD_NUM9;
Dcd_dat[1] = DCD_NUM9;
Dcd_dat[2] = DCD_NUM9 | DCD_DOT;
return;
}
value = d;
v5 = value % 10; value /= 10;
v4 = value % 10; value /= 10;
value = r;
v3 = value % 10; value /= 10;
v2 = value % 10; value /= 10;
v1 = value % 10; value /= 10;
if(r >= 100)
{
Dcd_dat[0] = DcdNum2Dat[v1];
Dcd_dat[1] = DcdNum2Dat[v2];
Dcd_dat[2] = DcdNum2Dat[v3] | DCD_DOT;
return;
}
if(r >= 10)
{
Dcd_dat[0] = DcdNum2Dat[v2];
Dcd_dat[1] = DcdNum2Dat[v3]| DCD_DOT;
Dcd_dat[2] = DcdNum2Dat[v4];
return;
}
Dcd_dat[0] = DcdNum2Dat[v3] | DCD_DOT;
Dcd_dat[1] = DcdNum2Dat[v4];
Dcd_dat[2] = DcdNum2Dat[v5];
return;
}
void DcdUpdate()
{
u8 seg, idx, dat;
if(Dcd_count <= 0)
return;
idx = Dcd_uct;
dat = Dcd_dat[idx];
seg = 1 << idx;
seg |= Dcd_exout;
DcdScan(seg, ~dat);
Dcd_uct ++;
if(Dcd_uct >= Dcd_count)
Dcd_uct = 0;
}