用了两周的时间完成了stc12的汇编代码编写与调试。有一些代码和生活的感悟记录一下。

代码分析

1.任务分析

其中先进行的任务分析。该任务需要ds18b20,lcd12864,和4*4矩阵键盘共同完成,最后加上PWM输出与PID调节。结构思路很清晰,需要完成的难点也很明了。接下来就是按部就班进行模块写作了。

2.系统基层规划

由于老师进一步提高了我的任务要求需要完成带小数的数据处理,所以有必要先谈谈数据结构————
1.存储的数字结构为ab.cd 其中ab为整数位,cd为小数位。两个变量紧邻分别存贮于对应的变量区。紧邻的意思是两个变量的寄存器地址在一起并且整数的寄存器为高地址,小数位的寄存器为低地址。

TEM_DATAL EQU 53H;数据保存低
TEM_DATAH EQU 54H;数据保存高

2.由于stc12的运行速度比51快于是需要完成us级延时函数的编写,并且需要修改ms级延时函数

DELAY_US:
REL_US:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DJNZ USL,REL_US
MOV USL,#99
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DJNZ USH,REL_US
MOV USH,#01
RET
DELAY_MS:
REL_MS:
MOV USH,#08
MOV USL,#05
LCALL DELAY_US
DJNZ MSL,REL_MS
MOV MSL,#99
MOV USH,#08
MOV USL,#05
LCALL DELAY_US
DJNZ MSH,REL_MS
RET

ms级的运行时间为对us级时间的计算,并经过示波器的数据进行调整而得到的。
3.寄存器的分配
由于有复杂的数学运算,所以需要提前规划一下地址分配
先行规划的是:

COMMON 3XH
PID-CACULATE 4XH
DS18B20 5XH
LCD 12864 6XH
4*4 KEY 7XH

后期由于PID运算复杂于是从其他位置选择了空的寄存器进行占用,但是总体分布就是这样。

2.DS18B20的底层框架与数据处理


根据18b20的数据手册进行的流程图编写,由于为单总线结构于是对于时序要求很高,开始使用的51单片机进行的仿真编写测试无误后添加到12单片机进行测试,发现无法读取正确数据,于是排查。最后发现由于代码执行时间不同导致时序紊乱。
再次主要记录一下数据处理部分

MOV LOOP_TEMP,#4
DATA_RRC: ;数据处理
CLR C
MOV A,TEM_DATAL
RLC A
MOV TEM_DATAL,A
MOV A,TEM_DATAH
RLC A
MOV TEM_DATAH,A ;将低字节高四位转移到高字节低四位
DJNZ LOOP_TEMP,DATA_RRC
MOV A,TEM_DATAL ;小数部分处理
SWAP A
MOV DPTR,#TEB20 ;通过查表更改小数值
MOVC A,@A+DPTR
MOV TEM_DATAL,A
RET
TEM_INIT:
SETB TEM_PIN
NOP
NOP
CLR TEM_PIN
MOV R0,#8
INTE: MOV R1,#185 ;设一个537us延时
KK1: DJNZ R1,KK1
DJNZ R0,INTE
SETB TEM_PIN
TEM_NO: MOV C,TEM_PIN ;循环检测
JC TEM_NO ;读到0证明检测成功
MOV USL,#76
MOV USH,#03H ;336US
LCALL DELAY_US
SETB TEM_PIN
RET
TEB20:
DB 00H,06H,0CH,13H,19H,1FH,20H,27H,32H,38H,3FH,45H,4BH,51H,52H,59H
; 00 6 12 19 25 31 32 39 50 56 63 69 75 81 82 89

该部分主要将读取的寄存器中的整数部分和小数部分进行了拆分处理,并将值进行了转化。小数的转化方法为查表,由于精度有限故可以采取查表方式记录小数点后两位。

3.LCD12864部分

LCD12864

该部分主要还是驱动操作部分,没有什么需要注意的地方,由于有时钟线,对于时序要求也不是很高。但是主要问题是————太慢,刷新五个数字需要大概100ms,简直不要太慢。
其中,显示函数中进行数字显示时对于变量处理采用显示哪个处理哪个的方法

;=======================================
; 	 设定显示值
;=======================================
MOV A,LCD_SETH
MOV B,#10
DIV AB
MOV LCD_TEMP,B
MOV LCD_ROW,#0B2H
MOV LCD_LINEH,#14H
MOV LCD_LINEL,#00H
LCALL LCD_DISPLAY1
MOV A,LCD_TEMP
MOV LCD_ROW,#0B2H
MOV LCD_LINEH,#14H
MOV LCD_LINEL,#09H
LCALL LCD_DISPLAY1
MOV LCD_ROW,#0B2H
MOV LCD_LINEH,#15H
MOV LCD_LINEL,#00H
MOV A,#16
LCALL LCD_DISPLAY1
MOV A,LCD_SETL
MOV B,#10
DIV AB
MOV LCD_TEMP,B
MOV LCD_ROW,#0B2H
MOV LCD_LINEH,#15H
MOV LCD_LINEL,#09H
LCALL LCD_DISPLAY1
MOV A,LCD_TEMP
MOV LCD_ROW,#0B2H
MOV LCD_LINEH,#16H
MOV LCD_LINEL,#00H
LCALL LCD_DISPLAY1
LCD_DISPLAY1:;写数字
MOV DPTR,#TEB8
MOV LCD_LOOP,#08H
MOV B,#8
MUL AB
MOV LCD_NUM,A
MOV B,A
LCALL LCD_DISP
INC LCD_ROW
MOV DPTR,#TEB9
MOV LCD_LOOP,#08H
MOV LCD_NUM,B
LCALL LCD_DISP
RET

由于12864需要分页分列写故一个数字需要写两页一列。

4.4*4按键部分

4*4键盘
00 1 2 3 P
04 4 5 6 I
07 7 8 9 D
特殊 OK 0 CANCEL SET
(竖列/横列)
数字计算元素
01 02 03 mode

此部分刚开始想的是查表法进行设计,但考虑到太没意思故耍了个酷采用逻辑计算的方式进行操作,整个数据结构也很清楚,模块主函数也很清楚。在此跟查表法的方法对比一下:

查表法 逻辑法
(可能是自创的)
由于是查表方便修改 采用固定模式不方便修改
主程序逻辑复杂,但是空闲阶段执行速度快 主程序逻辑简单但是空闲阶段执行速度略慢
子程序为顺序查找,最坏时间很长 整体程序为并行结构,每个结果的时间几乎等价

表中对于两者不同进行了展示,对于一般情况更倾向用查表,毕竟是通用方法。

;====================================================================
;按键主函数
;====================================================================
KEY_MAIN:
CHK_L:	    MOV P2,#0FFH
NOP
MOV P2,#0F0H
NOP
JNB  ROW1,ROW111;列检测
JNB  ROW2,ROW222
JNB  ROW3,ROW31
JNB  ROW4,ROW41
CHK_R:
MOV P2,#0FFH
NOP
MOV P2,#00FH
NOP
JNB  LINE1,LINE111
JNB  LINE2,LINE211;行检测
JNB  LINE3,LINE311
JNB  LINE4,LINE411
JB  KEY_OK,KEY_OK1			;如果按键没有松手不会继续进行以下步骤
JB  KEY_CANCEL,KEY_CANCEL1
CLR KEY_Y
CLR KEY_X
CHK_OK:	RET
ROW11:
MOV MSL,#01
MOV MSH,#01
LCALL DELAY_MS
JB  P2.3,KEY_CCC
JB KEY_Y,KEY_KKK
SETB KEY_Y
MOV KEY_TEMP4,KEY_TEMP3
MOV KEY_TEMP3,KEY_TEMP2
MOV  KEY_TEMP2,KEY_TEMP1
MOV KEY_TEMP1,KEY_DATAL
MOV KEY_DATAL,#00
AJMP CHK_R
LINE11:
JB KEY_MODFLAG,MOD_KP;	;如果按下了kp键
JNB KEY_Y ,CHK_OK		;必须先检测Y轴
JB KEY_X,CHK_OK			;检测X轴标志位
SETB KEY_X
MOV A,#01			    ;清除A且相加Y轴值
INC PWM_CCR
ADD A,KEY_DATAL
MOV KEY_DATAL,A
MOV LCD_KEYHH,LCD_KEYHL
MOV LCD_KEYHL,LCD_KEYLH
MOV LCD_KEYLH,LCD_KEYLL
MOV LCD_KEYLL,KEY_DATAL
AJMP CHK_L

5.PID部分

此部分除了算法全部自行设计,当时真的快想疯了,差点放弃,但最终还是一一解决了。当然此次过程再次验证了那个道理:自己挖的坑只可能自己填上,如果别人能填上1、这个坑很常规。2、你问的人曾经填过这个坑......

程序设计难点

1.小数部分的加入,导致计算量翻倍。
2.情况分类太多,正负号都需要考虑(还是c好.....)
3.乘法结果导致数据结果变成4位数。
4.中途乘法计算涉及到进位只能转换成16进制进行计算。
5.最后的16位结果计算得到应该传递出去的pwm值。

大概就是这么几部分,解决完成后写了将近500行。。。。

PID调节

程序大概结构

;PID计算函数
PID_CACULATE:
;加法
;入口参数 r0 r1 PID_FLAG1 PID_FLAG2
;出口参数 PID_TEMPL,PID_TEMPH,PID_FLAG
PID_ADD:
;乘法函数
;入口参数 r0,r1
;出口参数 PID_AA,PID_BB,PID_CC,PID_DD
PID_MUL:
;16进制加法函数
;入口参数 PID_FLAG1  PID_FLAG2   PID_ERRORD---A		PID_DD---AA
PID_ADD16:

大概就是这么几个函数。其中PID计算函数为主函数,其他三个函数为子函数做为调用就算的。
先写到这里回头继续☺