1. 实验背景与目标
2017-2018学年第一学期的嵌入式系统课程中,实验二"固件程序设计"是一个重要的实践环节。这个实验通常安排在单片机或嵌入式系统基础理论学习之后,旨在让学生通过实际编程掌握固件开发的核心技能。
固件(Firmware)是介于硬件和软件之间的特殊程序,它直接控制硬件设备的底层操作。与普通应用程序不同,固件通常存储在设备的非易失性存储器中,如ROM、EPROM或闪存。在嵌入式系统开发中,固件程序设计能力是工程师必备的核心技能之一。
本次实验的主要目标包括:
- 理解固件程序的基本概念和特点
- 掌握嵌入式开发环境的搭建和使用
- 学习固件程序的基本结构和编程方法
- 实现特定硬件功能的控制
- 掌握固件程序的调试和测试技术
2. 实验环境准备
2.1 硬件平台选择
在嵌入式系统实验中,硬件平台的选择至关重要。根据实验编号20155301-2015539推测,可能使用的是基于ARM Cortex-M系列或51系列单片机的开发板。这类开发板通常包含:
- 主控芯片(如STM32F103、AT89S52等)
- 基本外设(LED、按键、蜂鸣器等)
- 调试接口(JTAG/SWD或串口)
- 扩展接口(GPIO、I2C、SPI等)
提示:不同型号的开发板引脚定义可能不同,开始实验前务必查阅对应开发板的原理图和数据手册。
2.2 软件开发环境搭建
固件开发通常需要以下工具链:
集成开发环境(IDE):
- Keil μVision(适用于51和ARM)
- IAR Embedded Workbench
- Eclipse + ARM插件
编译器工具链:
- ARM-GCC
- SDCC(针对51系列)
调试工具:
- J-Link
- ST-Link
- 串口调试助手
辅助工具:
- 逻辑分析仪(如Saleae)
- 示波器(用于信号测量)
以Keil为例,安装步骤通常包括:
- 下载并安装MDK-ARM或C51版本
- 安装对应芯片的Device Family Pack
- 配置调试器参数
- 验证开发环境是否正常工作
2.3 工程创建与配置
新建Keil工程的基本流程:
- 选择正确的设备型号
- 设置工程保存路径
- 配置目标选项(Target Options):
- 输出格式(通常为HEX或BIN)
- 优化级别
- 调试设置
- 添加必要的库文件和启动文件
- 创建main.c源文件
3. 固件程序设计基础
3.1 固件程序的基本结构
典型的固件程序包含以下几个关键部分:
#include <reg52.h> // 或对应芯片的头文件 // 全局变量定义 unsigned int counter = 0; // 函数声明 void Delay(unsigned int ms); void Init_System(void); // 主函数 void main(void) { Init_System(); // 系统初始化 while(1) { // 主循环 // 主程序逻辑 P1 = ~P1; // 示例:端口取反 Delay(500); // 延时500ms } } // 系统初始化函数 void Init_System(void) { // 时钟配置 // 外设初始化 // 中断配置 } // 延时函数 void Delay(unsigned int ms) { unsigned int i,j; for(i=0;i<ms;i++) for(j=0;j<114;j++); }3.2 寄存器操作与位操作
在固件程序中,直接操作硬件寄存器是常见做法。以51单片机为例:
// 直接操作整个端口 P1 = 0x55; // 将P1端口设置为01010101 // 位操作(更推荐的方式) sbit LED = P1^0; // 定义P1.0为LED控制位 LED = 1; // 点亮LED LED = 0; // 熄灭LED // 使用位运算符 P1 |= 0x01; // 将P1.0置1 P1 &= ~0x02; // 将P1.1清0 P1 ^= 0x04; // 将P1.2取反3.3 中断服务程序设计
中断是固件程序中实现实时响应的关键机制。典型的中断服务程序框架:
// 中断服务程序示例(51系列) void Timer0_ISR(void) interrupt 1 { TH0 = 0xFC; // 重新装载定时器初值 TL0 = 0x66; counter++; // 中断计数器 } // 定时器初始化 void Timer0_Init(void) { TMOD &= 0xF0; // 设置定时器0为模式1 TMOD |= 0x01; TH0 = 0xFC; // 设置初值 TL0 = 0x66; ET0 = 1; // 使能定时器0中断 EA = 1; // 开启总中断 TR0 = 1; // 启动定时器0 }4. 实验内容实现
4.1 LED流水灯实现
LED控制是嵌入式系统最基本的实验之一。实现流水灯效果的典型代码:
#include <reg52.h> void Delay(unsigned int ms) { unsigned int i,j; for(i=0;i<ms;i++) for(j=0;j<114;j++); } void main() { unsigned char i; while(1) { for(i=0;i<8;i++) { P1 = ~(0x01 << i); // LED低电平点亮 Delay(200); // 延时200ms } } }常见问题及解决方法:
- LED不亮:检查硬件连接、限流电阻、IO口方向设置
- 流水速度异常:调整延时函数参数,或使用定时器精确控制
- LED亮度不均:检查各LED的限流电阻是否一致
4.2 按键检测实现
按键检测是交互设计的基础。以下是带消抖的按键检测实现:
sbit KEY = P3^2; // 假设按键接在P3.2 unsigned char Key_Scan() { if(KEY == 0) { // 检测按键按下 Delay(10); // 消抖延时 if(KEY == 0) { // 确认按键按下 while(!KEY); // 等待按键释放 return 1; // 返回按键按下标志 } } return 0; } void main() { while(1) { if(Key_Scan()) { P1 = ~P1; // 按键按下时取反P1端口 } } }注意:在实际产品中,建议使用定时器中断进行按键扫描,避免阻塞主程序。
4.3 串口通信实现
串口是嵌入式系统调试和数据传输的重要接口。51单片机串口初始化示例:
void UART_Init() { SCON = 0x50; // 模式1,允许接收 TMOD |= 0x20; // 定时器1模式2 TH1 = 0xFD; // 波特率9600@11.0592MHz TL1 = 0xFD; TR1 = 1; // 启动定时器1 ES = 1; // 使能串口中断 EA = 1; // 开启总中断 } void UART_SendByte(unsigned char dat) { SBUF = dat; while(!TI); // 等待发送完成 TI = 0; // 清除发送中断标志 } void UART_ISR() interrupt 4 { if(RI) { unsigned char recv = SBUF; RI = 0; // 处理接收数据 } }5. 调试与优化技巧
5.1 常见调试方法
- LED调试法:在关键位置添加LED状态指示
- 串口打印调试:通过串口输出变量值和程序状态
- 逻辑分析仪:捕获和分析数字信号时序
- 仿真调试:使用IDE的仿真功能单步执行程序
5.2 代码优化技巧
使用const和code关键字:将常量数据放入ROM
const unsigned char LED_Table[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};合理使用中断:避免在主循环中进行耗时操作
位操作替代算术运算:
// 不推荐 if(value % 2 == 0) // 推荐 if(value & 0x01 == 0)循环展开:减少循环开销
// 优化前 for(i=0;i<8;i++) { P1 = LED_Table[i]; Delay(100); } // 优化后 P1 = LED_Table[0]; Delay(100); P1 = LED_Table[1]; Delay(100); // ... 其余6个类似
5.3 功耗优化
- 不使用的外设模块及时关闭
- 合理使用CPU休眠模式
- 降低系统时钟频率(在满足需求的前提下)
- 使用中断唤醒代替轮询
6. 实验报告撰写要点
一份完整的固件程序设计实验报告应包含以下内容:
- 实验目的:明确实验要达成的目标
- 实验环境:详细列出硬件和软件环境
- 实验原理:阐述相关技术原理
- 实验内容:分步骤描述实现过程
- 实验结果:展示实验现象和数据
- 问题分析:记录遇到的问题和解决方法
- 实验总结:个人收获和改进建议
报告撰写注意事项:
- 代码部分应使用等宽字体,关键处添加注释
- 硬件连接应有示意图或照片
- 实验现象最好有视频或GIF动态展示
- 问题分析要具体,避免泛泛而谈
7. 进阶学习建议
完成基础实验后,可以尝试以下扩展内容:
- RTOS应用:在STM32上运行FreeRTOS或uC/OS
- 低功耗设计:实现基于中断唤醒的低功耗模式
- 外设驱动开发:编写LCD、传感器等外设驱动
- 通信协议实现:实现I2C、SPI等协议通信
- 固件升级设计:实现IAP(在应用编程)功能
推荐学习资源:
- 《嵌入式系统设计与实现》
- 《ARM Cortex-M3权威指南》
- Keil和IAR的官方文档
- 芯片厂商提供的参考手册和应用笔记
在实际项目开发中,固件工程师还需要掌握版本控制(Git)、单元测试、持续集成等工程实践技能。这些能力的培养需要长期的实践积累。