第五章与第六章属于硬件工作机制与存储器测试的介绍,由于不作深入了解,个人选择跳过该章节。但下图比较清晰的显示通信过程,因此贴在下面。
第七章主要介绍 1、控制与状态寄存器 2、设备驱动原理 3、时钟驱动 4、修改后的闪烁程序
1、控制与状态寄存器
外围设备有两种,一是与处理器包含在同一芯片称为内部外围设备,在芯片外部的为外部外围设备。在嵌入式系统中,这两种外围设备又可被称作存储映像外设以及输入输出外设。外围设备与芯片之间的最基本的接口是一组控制和状态寄存器。存储映像的控制与状态寄存器可以看做普通变量,需要声明一个指向寄存器的指针,并且显示设置指针值。例如:
volatile unsigned * pP2LTCH = (unsigned short *) 0x7200005E
其中 volatile 关键字,旨在在编译器中不要优化改变量。则程序变为
volatile unsigned * pP2LTCH = (unsigned short *) 0x7200005E
void
toggleLed(void)
{
*pP2LTCH ^= LED_GREEN;// x ^= y 等于 x = x^y
}
I/O映像寄存器主要问题在于C/C++没有标准的方法访问,只有特殊的机器指令,而指令无法支持C语言。只能用汇编或库例程读写。
2、设备驱动原理
设备驱动应该完全隐藏硬件,通常有5要素。
1、覆盖设备的存储映像控制以及状态存储器的数据结构
创建一个结构体struct 存放寄存器以及其偏移地址的表,从最低偏移处开始填充表,如果有位置没有用,则需要填充哑元变量。
2、跟踪目前硬件和设备状态的一组变量
3、一个把硬件初始化到已知状态的例程
4、合起来为设备驱动的用户提供API的一组例程
5、中断服务例程
3、时钟驱动 (80188EB处理器时钟为例)
C++类允许我们更好地隐藏硬件接口,防止应用程序意外地从程序其他部分读写设备寄存器。 Timer 类定义如下
enum TimerState{};
enum TimerState{};
class Timer
{
public:
Timer();
~Timer();
int start(unsigned int nMilliseconds,TimeType = OneShot);
int waitfor();
int cancel();
volatile TimerState state(); //Active、Idle、Done 防止编译优化
TimeType type(); // OneShot、Periodic
unsigned int length();
unsigned int count(); //记录剩余节拍数信息
Timer * pNext(); //指向下一个最先溢出的软件时钟
private:
static void interrupt Interrupt();// 中断服务例程
}
初始化
#include "i8018xEB.h" #include "timer.h" #define CYCLES_PER_TICK (25000/4) //80188EB为25MHz处理器
Timer::Timer(void)
{ static int bInitialized = 0;//初始指示标志 state = Idle; type = OneShot; length = 0; count = 0; pNext = NULL; if (!bInitialized) { gProcessoer.installHAndler(); //把中断服务例程插入中断向量表中 gProcessoer.pPCB->inControl.timerControl &= ~(Timer_MASK|Timer_PRIORITY); gProcessoer.pPCB->timer[2].count = 0; gProcessoer.pPCB->timer[2].maxCountA = CYCLES_PER_TICK; //maxCountA表示1ms内输入到时钟的时钟周期数 gProcessoer.pPCB->timer[2].control = Timer_ENABLE|Timer_INTERRUPT|Timer_PERIODIC;
bInitialized = 1; } }
全局对象 gProcessoer 在头文件 i8018xEB.h 中声明。全局数据结构PCB 覆盖了外设控制的存储映像寄存器,与时钟单元2相关的三个寄存器为这个256字节数据结构的一部分,为了美观,实现成一组嵌套式结构。可以通过gProcessoer.pPCB->timer[2].control 这种方式进行访问控制寄存器
类公共函数 start
int Timer::start(unsigned int nMilliseconds, TimerType timeType)
{
if (state != Idle)
{
return (-1);
}
state = Active;
type = timerType;
length = nMIlliseconds / MS_PER_STICK;
timerList.insert(this);
return (0);
}
类公共函数 interrrupt
void interrrupt Timer::Interuppt() { timerList.tick();
//tick方法为列表最顶端时钟count减1直至为0后改变state为done然后删除 gProcessoer.intControl.eoi = EOI_NONSPECIFIC; gProcessoer.pPCB->inControl.timerControl &= ~TIMER_MAXCOUNT; }
类公共函数 waitfor 会检查软件时钟是否到期
int Timer::waitfor()
{
if (state != Active)
{
return (-1);
}
while(state != Done);
if(type == Periodic)
{
state = Active;
timerList.insert(this);
}
else
{
state = Idle;
}
return (0);
}
类公共函数 cancel 删除时钟
void Timer::cancel(void )
{
if (state == Active)
{
timerList.remove(this);
}
state = Idle;
}
Timer 类还有其他一些函数,查看时钟是否活动,例如poll 它会返回 state == Done 的当前值。还有一特性称为callback ,
4、修改后的闪烁程序
当初实现计时是依靠估计nCycles– 的处理器速度,现在可以依靠时钟来精准定时。
#include "led.h"
#include "timer.h"
void main()
{
Timer timer;
time.start(500,Periodic)
while(1)
{
toggleLed(LED_GREEN);
timer.waitfor();
}
}
有必要在这里提到看门狗(watchdog )程序,它是一个恢复系统异常的普遍方法,与这里点亮LED很相似,如果没有给watchdog 相应,该程序即会判断出异常,重启系统。
转载请注明:XAMPP中文组官网 » 《C/C++嵌入式系统编程》读书笔记总结