首页 > 其他分享 >MCU第一次使用笔记-STC8H1K08

MCU第一次使用笔记-STC8H1K08

时间:2023-10-05 10:44:41浏览次数:42  
标签:PIN uchar STC8H1K08 笔记 tm ADC MCU pwm define

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









标签:PIN,uchar,STC8H1K08,笔记,tm,ADC,MCU,pwm,define
From: https://www.cnblogs.com/zzz3265/p/17743144.html

相关文章

  • 信息安全系统设计与实现课程第十一章学习笔记
    一、知识点归纳1.EXT2文件系统多年来,Linux一直使用EXT2(Card等1995)作为默认文件系统。EXT3(EXT3,2014)是EXT2的扩展。EXT3中增加的主要内容是一个日志文件,它将文件系统的变更记录在日志中°日志可在文件系统崩溃时更快地从错误中恢复。没有错误的EXT3文件系统与EXT2文件系......
  • [学习笔记] ex-KMP
    简介exKMP(扩展KMP算法),也叫Zalgorithm(Z算法),可以在\(\mathcal{O}(|s|+|t|)\)求解文本串\(s\)的所有后缀与匹配串\(t\)的最长公共前缀(LCP)。实现定义一个长度为\(n\)的字符串\(s\)的\(z\)函数\(z_i\)表示\(s\)长度为\(i\)的后缀与自身的最长公共前缀的长度......
  • [学习笔记] 线性基
    线性基是向量空间的一组基,通常可以解决有关异或的一些题目。——OIWiki线性基就是从初始集合中选出的一个子集,它满足一些性质,可以处理一些问题(屁话)。性质线性基中每个元素二进制下最高位是不同的。线性基中没有异或和为\(0\)的子集。线性基中任意子集中元素异或和的值......
  • [学习笔记] 树链剖分
    叫复习笔记或许更好。树链剖分就是把树剖成链去解决一些问题。定义重子节点:子节点中子树大小最大的节点。轻子节点:除重子节点外的其他子节点。重边:到重子节点的边。轻边:到轻子节点的边。记号\(dfn[x]\):DFS序,也是在线段树中的编号。\(son[x]\):重子节点。\(dep[x]\)......
  • [学习笔记] Tarjan 连通性全家桶
    拜谢陈老师的PPT!!!无向图割点若点\(x\)不为搜索树的根节点,则\(x\)是割点当且仅当搜索树上存在一个\(x\)的子节点\(y\)满足:\(dfn_x\lelow_y\)。特别地,当\(x\)是搜索树的根节点时,则\(x\)是割点当且仅当有两个点\(y_1,y_2\)满足上述条件。割边边\((x,y)\)是......
  • 笔记——线段树
    蓝月の笔记——线段树篇在树状数组中,我们讲解了关于单点修改区间查询的操作。今天,我们要讲一种更加高级的数据结构,他解决的是区间修改区间查询的问题多了一个区间当然更高级啦。这个数据结构就是——线段树Luogu-P3372给定一个长度为\(n\)的序列\(a_1,a_2,\cdots,a_n\)......
  • Linux运维学习笔记
    此笔记为学习https://www.bilibili.com/video/BV1nW411L7xm/?vd_source=3f851e85e66ef33269a2eefee664cec2的学习记录,目前持续更新中,希望能找到运维的实习吖 O(≧▽≦)OLinux的终端终端组成部分Linux关机命令shoutdown-hnow(正常关机)halt(关闭内存)init0使用VMware备......
  • 活动报名与缴费小程序开发笔记一
    项目背景活动报名与缴费小程序的开发背景主要源于以下几个因素:1.数字化时代的需求:随着移动互联网和智能手机的普及,人们习惯使用手机进行各种活动。传统的纸质报名表格和线下缴费方式变得相对繁琐,而数字化报名与缴费小程序提供了更便捷的解决方案。2.提高效率和减少人力成本:对于活......
  • 流畅的python笔记 (二) 2.序列构成的数组
    内置序列类型分类1:容器序列(能存放不同类型):list,tuple,collections.deque扁平序列(不能存放不同类型):str,bytes,bytearray,memoryview,array.array分类2:可变序列(能被修改):list,bytearray,array.array,collections.deque,memoryview不可变序列:tuple,str,bytes列表推导......
  • Python笔记
    第一章、Python概述1.1 扩展库安装方法使用pip命令安装扩展库。在cmd命令行中输入pip,回车后可以看到pip命令的使用说明。1.2 常用的pip命令pip命令示例说明pipfreeze[>requirements.txt]列出已安装扩展库及其版本号(不知道怎么用。。?)pipinstallSomePacka......