用了两周的时间完成了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部分

该部分主要还是驱动操作部分,没有什么需要注意的地方,由于有时钟线,对于时序要求也不是很高。但是主要问题是————太慢,刷新五个数字需要大概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按键部分

| 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_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计算函数为主函数,其他三个函数为子函数做为调用就算的。
先写到这里回头继续☺

Comments NOTHING