|

楼主 |
发表于 2020-3-29 10:55:50
|
显示全部楼层
接下来要点亮液晶屏。
大众款1602字符屏,控制芯片一般是HD44780或相似的。
虽是大众款,可芯片手册难见一份准确的,连初始化的几条指令流程都讲得不太清晰,各兼容芯片的手册都差不多。日货一向小气,估计此芯片的内部逻辑结构、设计意图、应用细节,只有厂商自珍了。所以让接口时序和指令耗时兼容各家产品的最慢者就行了,其它没多少好考究的。
4位接口模式的初始化流程:
- 上电后等待几十毫秒;
- 写B0011xxxx;
- 等待几毫秒;
- 写B0011xxxx;
- 等待几毫秒;
- 写B0011xxxx;
- 写B0010xxxx; //切换到4bit模式
- 分两次写B0010_10xx; //4bit数据接口,两行,5×7点阵
- 分两次写B0000_1000; //DisplayOff
- 分两次写B0000_0001; //DisplayClear
- 分两次写B0000_0110; //EntryModeSet
- 分两次写B0000_1101; //开显示
复制代码
虽然芯片规格称接口速度能到1MHz,但液晶模块里PCB走线细且长,又未适当接电源退耦电容,用示波器观察可见波形边沿形状不好。所以将控制脉冲放慢到2~3μs。
使用12MHz晶振时,传统51单片机一条指令耗时一、二μs,和HD44780配合较合适。现今的单时钟周期51单片机或其它高速单片机主频十几MHz以上,1μs能运行十多条指令,受影响明显。
虽然HD44780提供BUSY信号可查询,但控制指令总共就清屏、设置模式、设置光标、读写数据、读写地址这几条,执行耗时都是固定的,没必要去读BUSY信号。
况且读BUSY信号这个操作本身也和其它指令一样速度不高。
再有,网上见的资料大多没提到,读BUSY信号这个操作还须等上一次指令之后好几十微秒才能进行。呃,除了清屏、归零两条指令耗时1.5ms外,其它指令耗时均才37μs,比等候BUSY信号能用还快咧。
HD44780每行的显存是40个字符,1602屏每行只可显示16个字符。
屏幕滚动的功能似乎没什么用,估计不太会用它去做滚动广告、屏保之类。对显示效果要求不高,一般也不会去搞两屏内容快速切换。
因此写几个常用的功能就够。
- void LcdLocate(int8u row, int8u col); //指定字符显示位置。
- void LcdPrint(int8u c); //显示一个字符。
- void LcdPrintString(int8u row, int8u col, int8u *str); //依次显示str中的字符,直至'\0'。不考虑超出16列、换行。
- void LcdClearRow(int8u row); //其实就是从行首位置起显示16个空格。
复制代码
例如,程序初始的界面:
- LcdInit();
- LcdPrintString(1, 1, " Spot Welder");
- LcdPrintString(2, 1, " 2020-02");
复制代码
接下来是按键。
设置一个定时中断,每1ms扫描一遍按键,记录每个按键的状态、持续时间。当连续若干次的状态不变时,才认为按键已稳定。
通常微动开关的按键抖动在几毫秒以内。若要过滤50Hz市电线路的干扰,可将判断时间加长到几十毫秒,不过按键的响应也会相应延迟。这个时间值可做进参数设置功能里,让用户自由变更。
在菜单操作中,按+、-键调节数值时,短按一次增减1步长,若持续按键达一两秒则连续自动调节,例如一秒重复10次。
大范围的调节,例如“触发延迟10~15000μs,调节步长10μs”,一秒重复10次的话,持续按键要150秒才能调到头,显然太久。一般按着键十几秒估计就令人厌烦了。
因此须判断当持续按键超过例如3秒后,进一步加速,例如一秒重复100次。
有些产品按键很少,看似简洁,但用起来要区分短按、长按,功能复用太多,很麻烦。
这里准备6个按键:设置,取消,减,增,确认,焊接。
按〖设置〗进入参数设置菜单,〖减〗〖增〗移动光标,〖确认〗进入该项,〖取消〗退回上一级菜单。
在参数项目中,按〖减〗〖增〗进行调节,持续按着可快速调节,按〖确认〗保存,〖取消〗则放弃更改。
调试观察,扫描一次6个按键要耗好几百步。传统51单片机接12MHz晶振时,1ms里有六七百μs都用来处理按键了。
简单控制类的应用通常运算量不多,需要的是响应速度。按上述情况,若不用高优先级中断,就要等几百微秒处理完按键之后再来响应其它事件,而且剩下的处理能力只剩两百多步了。
例如控制步进电机,一圈200个脉冲,每秒5转,则每1ms要处理一个脉冲,1ms内只剩两百多μs来处理,较吃力。
换成现今的单周期51,速度翻十几倍,1ms里只用去了几十μs,能充分迅速地响应其它事件。
现在做这个点焊机控制,没什么需要高速响应的控制,焊接动作那几百毫秒精确计时期间可暂停按键、液晶屏等其它处理,大众款51足以胜任了。
接下来是存储器。
需要保存的几个参数:
交流电过零点之后多久触发。
第一次焊接时间。
第一次焊接之后等待时间。
第二次焊接时间。
第二次焊接之后等待时间。
交流过零检测电路是个电压比较器,检测到电压低于一定值时动作,在零点左右产生一个约1ms宽的脉冲。
程序可能是在零点之前捕捉到,则延时几百μs后即零点。或是零点之后才捕捉到,则下个半波零点是9点几ms之后。
为了保持磁平衡,令变压器每次通电整数个全波,因此零点之后才捕捉到的,下个过零点选在19点几ms之后。
于是,该参数的设置范围是0~20000μs。
整机做好后,用示波器观察程序捕捉到的零点时刻,减去接触器机械动作延迟时间,来做设定。小继电器的动作时间大概是数毫秒,大个头的接触器不知如何。
不用示波器的话,也可观察接触器触点通断时的火花,调节达到火花最小即可。
据说先短焊第一次,可去除氧化层、预热,紧接着焊第二次,这样的效果好。因此预留了两组焊接、等待的时间参数。
为了保持磁平衡,焊接时间取20ms的整数倍,范围定20~2000ms吧。
焊接时间也可短到10ms的倍数,程序里记录是在正半周还是负半周的过零点触发的,下次交换即可。估计20ms够短了,先不考虑太复杂的。
焊接之间的间隔,感觉100~2000ms范围可以了。
AT24Cxx存储器,便宜,IIC接口不复杂。
为防芯片上电自动复位失败,程序应对其发指令复位。方法见芯片手册,通常发至多9个SCL时钟就能完成。
只读写几个字节,不需考虑连续读写、页长度之类的,做两个子程序就好。
- void At24cByteWrite(int8u addr, int8u dat);
- int8u At24cRandomRead(int8u addr);
复制代码
Keil C51将多字节整数按高位字节先行,保存到AT24Cxx时按同样顺序就好。
例如保存一个2字节整数4779,可在存储器地址0x00存0x12、地址0x01存0xAB。
硬件部分基本好了。接下来是菜单操作过程。
按〖设置〗键,进入菜单。
按〖减〗〖增〗移动光标,〖确认〗进入该项,〖取消〗退回上一级菜单。
按〖减〗〖增〗进行调节数值,持续按着可快速调节,按〖确认〗保存,〖取消〗则放弃更改。
退出最初级菜单后,回到等待焊接状态。
各项参数都是简单整数,调节过程都是相似的,只是提示文字、数值范围不同。将不同的部分定义一个结构体
- typedef struct
- {
- int8u *Title;
- int8u *Unit;
- int16u Value;
- int16u ValueMin;
- int16u ValueMax;
- int16u ValueAdj;
- } INPUT_DIALOG;
复制代码
做一个子程序InputDialog()来统一调用,比较简洁。例如设置触发延时:
- ……
- INPUT_DIALOG dialog;
- dialog.Title = "Trig Delay";
- dialog.Unit = "us";
- dialog.Value = (int16u)At24cRandomRead(ADDR_TRIG_DELAY) << 8;
- dialog.Value |= At24cRandomRead(ADDR_TRIG_DELAY + 1);
- dialog.Value = dialog.Value / 10 * 10;
- dialog.ValueMin = 0;
- dialog.ValueMax = 20000;
- dialog.ValueAdj = 10;
- InputDialog(&dialog);
- ……
复制代码
主程序部分就简单了,按〖设置〗键就进入参数设置菜单,按〖焊接〗则暂停扫描按键、等待过零信号、驱动继电器。
- void main()
- {
- LcdPrintString(1, 1, " Spot Welder");
- LcdPrintString(2, 1, " 2020-02");
- LoadConfig();
- while(1)
- {
- if (KeyIsPressed(KEY_SETUP))
- {
- Menu();
- LoadConfig();
- }
- else if (KeyIsPressed(KEY_WELD))
- {
- //暂停按键扫描
- //等待过零信号
- Delay_us_2(cfg_TrigDelay);
- RELAY = RELAY_ON;
- Delay_ms(cfg_WeldingTime1);
- RELAY = RELAY_OFF;
- Delay_ms(cfg_WaitingTime1);
- RELAY = RELAY_ON;
- Delay_ms(cfg_WeldingTime2);
- RELAY = RELAY_OFF;
- Delay_ms(cfg_WaitingTime2);
- //恢复按键扫描
- }
- }
- }
复制代码
|
|