关键词不能为空

当前您在: 大学查询网 > 高校介绍 >

河南大学老校区单片机程序框架

作者:高考题库网
来源:https://bjmy2z.cn/daxue
2020-12-08 15:13
tags:

-

2020年12月8日发(作者:晏砺堂)


大家来侃侃单片机的裸奔程序的框架呀!

以下是我总结的一些东西,

不合乎之处来请大家指


点呀,本人第二次在

21ic

发 帖,希望大家鼓励鼓励呀!



07

年参加全国大学生电子设计大赛初次接触单片机开发至今已经有

4

年了,初学单片机


时,都会纠结于其各个模块功能的应用,如串 口(

232

485

)对各种功能

IC

的控制

,

电机


控制

P WM

,中断应用,定时器应用,人机界面应用,

CAN

总线等

.

这是一个学习过程中必


需的阶段,是基本功。很庆幸,在 参加电子设计大赛赛前培训时,

MCU

周围的控制都训练


的很扎实。经过这个阶段后,后来接触不同的

MCU

就会发现,都大同小异,各有 各的优势


而已,学任何一种新的

MCU

都很容易入手包括 一些复杂的处理器。而且对

MCU

的编程控


制会提升一个 高度概况

——

就是对各种外围进行控制

(

如果是对 复杂算法的运算就会


DSP

了)

而外围与

MCU

的通信方式一般也就几种时序:

IIC,SPI,intel8080,M6800


样看来

MCU

周围的编程就是一个很简单的东西了。


然而这只是嵌入式开发中 的一点皮毛而已,

在接触过多种

MCU,

接触过复杂设计要求,< /p>


跑过操作系统等等后,

我们在回到单片机的裸机开发时,

就 不知不觉的就会考虑到整个程序


设计的架构问题;一个好的程序架构,是一个有经验的工 程师和一个初学者的分水岭。


以下是我对单片机程序框架以及开发中一些常用部分的认识总结:


任何对时间要求苛刻的需求都是我们的敌人,在必要的时候我们只有增加硬件成本来消灭


它;

比如你要

8

个数码管来显示,

我们 在没有相关的硬件支持的时候必须用

MCU

以动态扫


描的 方式来使其工作良好;

而动态扫描将或多或少的阻止了

MCU

处理 其他的事情。

MCU


负担很重的场合,我会选择选用一 个类似

max8279

外围

ic

来解决这个困扰;


然而庆幸的是,有着许多不是对时间要求苛刻的事情:


例如键盘的扫描,

人们敲击键盘的速率是有限的,

我们无 需实时扫描着键盘,

甚至可以每隔


几十

ms

才去扫描一下;然而这个几十

ms

的间隔,我们的

MCU

还可以完成许多的事情;


单片机虽然是裸机奔跑,

< p>但是往往现实的需要决定了我们必须跑出操作系统的姿态

——

多任

< p>
务程序;


比如一个常用的情况有

4

个任务:


1

键盘扫描;


2

led

数码管显示;


3

串口数据需要接受和处理

;


4

串口需要发送数据;


如何来构架这个单片机的程序将是我们的重点;



读书时代的我会把键盘扫描用查询的方式放在主循环中,

而串口接收数据用中断,

在中断服


务函数中组成相应的帧格式 后置位相应的标志位,

在主函数的循环中进行数据的处理,

串口

< br>发送数据以及

led

的显示也放在主循环中;



这样整个程序就以标志变量的通信方式,相互配合的在主循环 和后台中断中执行;


然而必须指出其不妥之处:


每个任务的时间片可能过长,

这将导致程序的实时性能差。

如 果以这样的方式在多加几个任


务,

使得一个循环的时间过长,

< p>可能键盘扫描将很不灵敏。

所以若要建立一个良好的通用编


程模型,

我们必须想办法,

消去每个任务中费时间的部分以及把每个任务再次分解;

下面来


细谈每个任务的具体措施:


1

键盘扫描


键盘扫描是单片机的常用函数,

以下指出常用的键盘扫描程序中,

严重阻碍系统实时性能的


地方;


众所周知,一个键按下之后的波形是这样的(假定低有效)


在有键按下后,

数据线上的信号出现一段时间的抖动 ,然后为低,

然后当按键释放时,

信号


抖动一段时间后变 高。

当然,

在数据线为低或者为高的过程中,

都有可能出现一些很 窄的干


扰信号。


unsigned char kbscan(void)


{


unsigned char sccode,recode;


P2=0xf8;


if ((P2&0xf8)!=0xf8)


{


delay(100);

//

延时

20ms

去抖

--------

这里太费时了,很糟糕


if((P2&0xf8)!=0xf8)


{


sccode=0xfe;


while((sccode&0x08)!=0)


{


P2=sccode;


if ((P2&0xf8)!=0xf8)


break;


sccode=(sccode<<1)|0x01;


}


recode=(P2&0xf8)|0x0f;


return(sccode&recode);


}


}


return (KEY_NONE);


}


键盘扫描是需要软件去抖的,这 没有争议,然而该函数中用软件延时来去抖(

ms

级别的延


时)

,这是一个维持系统实时性能的一个大忌讳;


一般还有一个判断按键释放的代码:


While( kbscan() != KEY_NONE)


; //

死循环等待


这样很糟 糕,

如果把键盘按下一直不放,

这将导致整个系统其它的任务也不能执行,

这将是


个很严重的

bug


有人会这样进行处理:


While(kbsan() != KEY_NONE )


{


Delay(10);


If(Num++ > 10)


Break;


}


即在一定得时间内,

如果键盘一直按下,

将作为有效键处理。

这样虽然不导致整个系统 其它


任务不能运行,但也很大程度上,削弱了系统的实时性能,因为他用了延时函数;< /p>






我们用两种有效的方法来解决此问题:


1

在按键功能比较简单的情况下,我们仍然用上面的

k bscan()

函数进行扫描,只是把其中


去抖用的软件延时去了,把去 抖以及判断按键的释放用一个函数来处理,它不用软件延时,


而是用定时器的计时(用一 般的计时也行)来完成;代码如下


void ClearKeyFlag(void)


{


KeyDebounceFlg = 0;


KeyReleaseFlg

= 0;


}



void ScanKey(void)


{


++KeyDebounceCnt;//

去抖计时(这个计时也可以放在 后台定时器计时函数中处理)


KeyCode = kbscan();


if (KeyCode != KEY_NONE)


{


if (KeyDebounceFlg)//

进入去抖状态的标志位


{


if (KeyDebounceCnt > DEBOUNCE_TIME)//

大于了去抖规定的时间


{


if (KeyCode == KeyOldCode)//

按键依然存在,则返回键值


{


KeyDebounceFlg = 0;


KeyReleaseFlg

= 1;//

释放标志


return;

//Here exit with keycode


}


ClearKeyFlag();

//KeyCode != KeyOldCode

,只是抖动而已


}


}else{


if (KeyReleaseFlg == 0)


{


KeyOldCode

= KeyCode;


KeyDebounceFlg = 1;


KeyDebounceCnt = 0;


}else{


if (KeyCode != KeyOldCode)


ClearKeyFlag();


}


}


}else{


ClearKeyFlag();//

没有按键则清零标志


}


KeyCode = KEY_NONE;


}




在按键情况较复杂的情况,如有长 按键,

组合键,连键等一些复杂功能的按键时候,

我们跟


倾向于用

状态机来实现键盘的扫描


//avr

单片机

4*3

扫描状态机实现


char read_keyboard_FUN2()


{


static char key_state = 0, key_value, key_line,key_time;


char key_return = No_key,i;


switch (key_state)


{


case 0: //

最初的状态,进行

3*4

的键盘扫描


key_line = 0b00001000;


for (i=1; i<=4; i++) //

扫描键盘


{


PORTD = ~key_line; //

输出行线电平


PORTD = ~key_line; //

必须送

2

次!

!< /p>

(注

1


key_value = Key_mask & PIND; //

读列电平


if (key_value == Key_mask)


key_line <<= 1; //

没有按键,继续扫描


else


{


key_state++; //

有按键,停止扫描


break; //

转消抖确认状态


}


}


break;


case 1: //

此状态来判断按键是不是抖动引起的


if (key_value == (Key_mask & PIND)) //

再次读列电平,


{


key_state++; //

转入等待按键释放状态


key_time=0;


}


else


key_state--; //

两次列电平不同返回状态

0

(消抖处理)


break;


case 2: //

等待按键释放状态


PORTD = 0b00000111; //

行线全部输出低电平


PORTD = 0b00000111; //

重复送一次


if ( (Key_mask & PIND) == Key_mask)

-


-


-


-


-


-


-


-



本文更新与2020-12-08 15:13,由作者提供,不代表本网站立场,转载请注明出处:https://bjmy2z.cn/daxue/21097.html

单片机程序框架的相关文章