MCU第一次使用笔记-STC8H1K08

发布时间 2023-10-05 10:36:33作者: Yofoo
  1. 计时中断开不起来:
    需要开启定时器, 开启总中断控制
    ET0 = 1;
    EA = 1;

  2. PWM 端口指定, 按示例无法使用其他端口
    更改输出端口需要修改 PWMA_CCER1, PWMA_ENO, 文档描述看的不是太明白

  3. ADC 使用时需要配置端口状态, 还有上拉电阻, 另外实际使用时跳动非常大
    尝试了很多方法:
    a. VCC 使用更好的电源/电池
    b. Ref用的TL431去掉
    c. VCC/Ref 加大电容
    d. 检测信号直接用电池
    e. 修改ADC速度, 读取周期等参数
    这些方法都没有效果, 最后发现修改 RESFMT 解决问题
    ADCCFG中的RESFMT使用0时, 买的STC8H1K08-SSOP20 有问题,跳动非常大, RESFMT使用1时正常

  4. 读取8位以上寄存器同步问题
    如一个32位变量在定时中断中自加, 外部访问时发生错位问题, 解决方法:
    a. 使用类似总线中的busy标记
    b. 读取前后开关系统中断
    c. 读取两次,然后比较数据校正, 等还有其他比较多方法

  5. 按键或其他输入消抖或等其他, 以及输入时间检测都需要计时, 有个计时系统是很有必要的
    按键使用计数判断点击, LED输出用计数保持状态

  6. 旋转编码器检测的间隔用1-4ms, 太长就会出现误报情况

  7. 数码管每个总循环显示一个字符, 这样效果会更好(内部储存需要显示的全数据)

#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;
}