8051模板移植
8051模板移植
- 一,新建工程文件
- 二,Keil配置
一,新建工程文件
在工程文件下建立Driver和User
打开Keil,点击扳手选择芯片型号
出现下图情况,选择是,然后会多出一个启动文件,以后有用
二,Keil配置
按照下图,勾选生成hex文件
将桌面上的头文件路径添加到Keil
建立main.c文件,保存到User
将下面的代码粘贴到main.c
/*** 包含的头文件区域*/
// 芯片相关头文件
#include <STC15F2K60S2.H>// 自定义外设头文件
#include "led.h" // LED显示驱动
#include "key.h" // 按键驱动
#include "seg.h" // 数码管驱动
#include "iic.h" // IIC总线通信
#include "onewire.h" // 单总线协议(DS18B20温度传感器)
#include "uart.h" // 串口通信
#include "ultrasound.h" // 超声波测距
#include "ds1302.h" // 实时时钟
#include "init.h" // 系统初始化// 系统头文件
#include "stdio.h" // 标准输入输出
#include "string.h" // 字符串处理
#include "intrins.h" // 内联汇编指令/*** 全局变量声明区*/
// 按键相关变量
idata unsigned char Key_Val; // 当前按键值
idata unsigned char Key_Down; // 按键按下标志
idata unsigned char Key_Old; // 上次按键值
idata unsigned char Key_Up; // 按键释放标志
idata unsigned char Key_Slow_Down; // 按键消抖延时计数器// 数码管显示相关变量
pdata unsigned char Seg_Buf[8] = {10, 10, 10, 10, 10, 10, 10, 10}; // 数码管显示缓冲区,初始为全不显示
idata unsigned char Seg_Pos; // 当前扫描的数码管位置
idata unsigned int Seg_Slow_Down; // 数码管显示更新延时计数器// LED显示相关变量
pdata unsigned char ucLed[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // LED显示缓冲区// 串口通信相关变量
idata unsigned char Uart_Recv_Tick; // 串口接收超时计数器
idata unsigned char Uart_Rx_Flag; // 串口接收标志
idata unsigned char Uart_Recv[10]; // 串口接收数据缓冲区,默认10个字节,可根据需要调整
idata unsigned char Uart_Recv_Index; // 串口接收数据索引// 频率计相关变量
idata unsigned int Freq; // 频率值
idata unsigned int Time_1s; // 1秒计时器// 实时时钟相关变量
pdata unsigned char ucRtc[3] = {11, 12, 13}; // 时、分、秒
idata unsigned char RTC_Slow_Down; // 时钟读取延时计数器// 传感器相关变量
idata unsigned int Temperature_Val_100x; // 温度值(放大100倍)
idata unsigned int AD_Light_Val_100x; // 光敏电阻值(放大100倍)
idata unsigned int AD_RB2_Val_100x; // 滑动变阻器值(放大100倍)
idata unsigned char AD_Slow_Down; // AD转换延时计数器
idata unsigned int Temperature_Slow_Down; // 温度读取延时计数器
idata unsigned char Distance_Val; // 超声波测距距离值
idata unsigned char Distance_Slow_Down; // 超声波测距延时计数器// PWM调光相关变量
idata unsigned char pwm_period = 10; // PWM周期值
idata unsigned char pwm_compare = 1; // PWM比较值(占空比)// 显示模式控制
idata unsigned char Seg_Show_Mode; // 显示模式:0-时间、1-温度、2-距离、3-光敏+变阻器、4-频率/*** 功能函数区*//*** AD/DA转换处理函数* 功能:读取AD转换值并输出DA值*/
void AD_DA()
{// 延时控制,限制AD转换频率if (AD_Slow_Down < 160)return;AD_Slow_Down = 0;// 读取滑动变阻器AD值(通道0x43)并转换为百分比(放大100倍)AD_RB2_Val_100x = Ad_Read(0x43) * 100 / 51.0;// 读取光敏电阻AD值(通道0x41)并转换为百分比(放大100倍)AD_Light_Val_100x = Ad_Read(0x41) * 100 / 51.0;// 输出DA值(2V)Da_Write(102);
}/*** 实时时钟读取函数* 功能:从DS1302读取当前时间*/
void Get_Time()
{// 延时控制,限制读取频率if (RTC_Slow_Down < 100)return;RTC_Slow_Down = 0;// 读取时钟数据Read_Rtc(ucRtc);
}/*** 温度读取函数* 功能:从DS18B20读取温度值*/
void Get_Temperature()
{// 延时控制,限制读取频率if (Temperature_Slow_Down < 300)return;Temperature_Slow_Down = 0;// 读取温度并放大100倍,便于处理小数Temperature_Val_100x = rd_temperature() * 100;
}/*** 超声波测距函数* 功能:获取超声波测距距离*/
void Get_Distance()
{// 延时控制,限制测距频率if (Distance_Slow_Down < 100)return;Distance_Slow_Down = 0;// 获取超声波距离值Distance_Val = Ut_Wave_Data();
}/*** 按键处理函数* 功能:扫描按键并处理按键事件*/
void Key_Proc()
{// 延时控制,按键消抖if (Key_Slow_Down < 10)return;Key_Slow_Down = 0;// 读取当前按键值Key_Val = Key_Read();// 检测按键下降沿(按下瞬间)Key_Down = Key_Val & (Key_Old ^ Key_Val);// 检测按键上升沿(释放瞬间)Key_Up = ~Key_Val & (Key_Old ^ Key_Val);// 保存当前按键值作为下次扫描的旧值Key_Old = Key_Val;// 按键4:切换显示模式if (Key_Down == 4){Seg_Show_Mode = (++Seg_Show_Mode) % 6; // 循环切换显示模式}// 按键8:增加PWM占空比if (Key_Down == 8)pwm_compare = (++pwm_compare) % 10;// 按键9:减少PWM占空比if (Key_Down == 9)pwm_compare = (pwm_compare == 0) ? 0 : pwm_compare - 1;
}/*** 数码管显示处理函数* 功能:根据当前显示模式更新数码管显示数据*/
void Seg_Proc()
{// 延时控制,限制显示刷新频率if (Seg_Slow_Down < 500)return;Seg_Slow_Down = 0;// 根据当前显示模式处理数据switch (Seg_Show_Mode){case 0:// 模式0:显示时间(时:分:秒)Seg_Buf[0] = ucRtc[0] / 10; // 时-十位Seg_Buf[1] = ucRtc[0] % 10; // 时-个位Seg_Buf[2] = 10; // 空位(分隔符)Seg_Buf[3] = ucRtc[1] / 10; // 分-十位Seg_Buf[4] = ucRtc[1] % 10; // 分-个位Seg_Buf[5] = 10; // 空位(分隔符)Seg_Buf[6] = ucRtc[2] / 10; // 秒-十位Seg_Buf[7] = ucRtc[2] % 10; // 秒-个位break;case 1:// 模式1:显示温度值(带小数点)Seg_Buf[0] = Temperature_Val_100x / 1000; // 温度-十位Seg_Buf[1] = Temperature_Val_100x / 100 % 10 + ','; // 温度-个位(带小数点)Seg_Buf[2] = Temperature_Val_100x / 10 % 10; // 温度-小数第一位Seg_Buf[3] = Temperature_Val_100x % 10; // 温度-小数第二位Seg_Buf[4] = 10; // 空位Seg_Buf[5] = 10; // 空位Seg_Buf[6] = 10; // 空位Seg_Buf[7] = 10; // 空位break;case 2:// 模式2:显示超声波测距距离Seg_Buf[0] = Distance_Val / 100; // 距离-百位Seg_Buf[1] = Distance_Val / 10 % 10; // 距离-十位Seg_Buf[2] = Distance_Val % 10; // 距离-个位Seg_Buf[3] = 10; // 空位Seg_Buf[4] = 10; // 空位Seg_Buf[5] = 10; // 空位Seg_Buf[6] = 10; // 空位Seg_Buf[7] = 10; // 空位break;case 3:// 模式3:显示AD转换值(光敏+滑动变阻器)Seg_Buf[0] = AD_Light_Val_100x / 100 + ','; // 光敏-整数位(带小数点)Seg_Buf[1] = AD_Light_Val_100x / 10 % 10; // 光敏-小数第一位Seg_Buf[2] = AD_Light_Val_100x % 10; // 光敏-小数第二位Seg_Buf[3] = 10; // 空位Seg_Buf[4] = 10; // 空位Seg_Buf[5] = AD_RB2_Val_100x / 100 + ','; // 变阻器-整数位(带小数点)Seg_Buf[6] = AD_RB2_Val_100x / 10 % 10; // 变阻器-小数第一位Seg_Buf[7] = AD_RB2_Val_100x % 10; // 变阻器-小数第二位break;case 4:// 模式4:显示频率值Seg_Buf[0] = Freq / 10000000; // 频率-千万位Seg_Buf[1] = Freq / 1000000 % 10; // 频率-百万位Seg_Buf[2] = Freq / 100000 % 10; // 频率-十万位Seg_Buf[3] = Freq / 10000 % 10; // 频率-万位Seg_Buf[4] = Freq / 1000 % 10; // 频率-千位Seg_Buf[5] = Freq / 100 % 10; // 频率-百位Seg_Buf[6] = Freq / 10 % 10; // 频率-十位Seg_Buf[7] = Freq % 10; // 频率-个位break;}// 调试输出示例(注释状态)// printf("%f,%bu,%f,%f,%u\r\n",// (float)Temperature_Val_100x / 100.0f,// Distance_Val,// (float)AD_Light_Val_100x / 100.0f,// (float)AD_RB2_Val_100x / 100.0f,// Freq);
}/*** LED灯显示处理函数* 功能:控制LED灯显示*/
void Led_Proc()
{// 设置所有LED灯亮ucLed[0] = 1;ucLed[1] = 1;ucLed[2] = 1;ucLed[3] = 1;ucLed[4] = 1;ucLed[5] = 1;ucLed[6] = 1;ucLed[7] = 1;
}/*** 串口通信处理函数* 功能:处理接收到的串口数据*/
void Uart_Proc()
{unsigned char x, y;// 无数据接收时直接返回if (Uart_Recv_Index == 0)return;// 接收超时处理(10ms无新数据视为一帧结束)if (Uart_Recv_Tick >= 10){Uart_Rx_Flag = 0;Uart_Recv_Tick = 0;// 数据解析示例:解析"x,y"格式的坐标数据if (sscanf(Uart_Recv, "%bu,%bu", &x, &y) == 2)printf("my get x=%bu,y=%bu", x, y);elseprintf("error");// 清空接收缓冲区,准备下一次接收memset(Uart_Recv, 0, Uart_Recv_Index);Uart_Recv_Index = 0;}
}/*** 定时器0初始化函数* 功能:配置定时器0工作在计数模式,用于频率测量* 频率:外部输入*/
void Timer0_Init(void)
{AUXR &= 0x7F; // 定时器时钟12T模式TMOD &= 0xF0; // 清除定时器0模式位TMOD |= 0x05; // 设置为计数模式,计数外部输入脉冲TL0 = 0x00; // 计数器低8位清零TH0 = 0x00; // 计数器高8位清零TF0 = 0; // 清除TF0溢出标志TR0 = 1; // 启动定时器0计数
}/*** 定时器1初始化函数* 功能:配置定时器1工作在定时模式,周期为1ms* 频率:@12.000MHz晶振*/
void Timer1_Init(void) // 1毫秒@12.000MHz
{AUXR &= 0xBF; // 定时器时钟12T模式TMOD &= 0x0F; // 设置定时器模式TL1 = 0x18; // 设置定时初始值TH1 = 0xFC; // 设置定时初始值TF1 = 0; // 清除TF1标志TR1 = 1; // 定时器1开始计时ET1 = 1; // 使能定时器1中断EA = 1; // 使能总中断
}/*** 定时器1中断服务函数* 功能:系统主要定时任务处理* 周期:1ms*/
void Timer1_Isr(void) interrupt 3
{// 各模块计时器递增Key_Slow_Down++;Seg_Slow_Down++;RTC_Slow_Down++;Temperature_Slow_Down++;AD_Slow_Down++;Distance_Slow_Down++;// 数码管动态扫描控制if (++Seg_Pos == 8)Seg_Pos = 0;// 数码管显示处理(带小数点判断)if (Seg_Buf[Seg_Pos] > 20)Seg_Disp(Seg_Pos, Seg_Buf[Seg_Pos] - ',', 1); // 显示带小数点elseSeg_Disp(Seg_Pos, Seg_Buf[Seg_Pos], 0); // 显示无小数点// PWM调光处理if (++pwm_period >= 10)pwm_period = 0;if (pwm_period >= pwm_compare)Led_Disp(ucLed); // PWM高电平时显示LEDelseLed_Off(); // PWM低电平时关闭LED// 串口接收超时计数if (Uart_Rx_Flag == 1)Uart_Recv_Tick++;// 频率计1秒采样控制if (++Time_1s == 1000){Time_1s = 0;Freq = TH0 << 8 | TL0; // 读取定时器0计数值作为频率值TH0 = TL0 = 0; // 清零计数器,开始下一次计数}
}/*** 串口1中断服务函数* 功能:处理串口接收中断*/
void Uart1Server() interrupt 4
{if (RI == 1) // 接收中断{Uart_Rx_Flag = 1; // 设置接收标志Uart_Recv_Tick = 0; // 清零接收超时计数器Uart_Recv[Uart_Recv_Index] = SBUF; // 保存接收数据Uart_Recv_Index++; // 接收索引增加RI = 0; // 清除接收中断标志// 接收缓冲区溢出保护if (Uart_Recv_Index > 10){Uart_Recv_Index = 0;memset(Uart_Recv, 0, 10); // 清空接收缓冲区}}
}/*** 主函数* 功能:系统初始化和主循环*/
void main()
{// 系统初始化System_Init(); // 初始化系统基本配置Set_Rtc(ucRtc); // 设置初始时间Timer0_Init(); // 初始化定时器0(频率计)Uart1_Init(); // 初始化串口Timer1_Init(); // 初始化定时器1(系统定时)// 系统主循环while (1){Key_Proc(); // 按键处理Seg_Proc(); // 数码管显示处理Led_Proc(); // LED显示处理Uart_Proc(); // 串口通信处理AD_DA(); // AD/DA转换处理Get_Time(); // 时钟读取Get_Distance(); // 超声波测距处理Get_Temperature(); // 温度读取处理}
}
将模板粘贴到Driver下
接下来将桌面上的文件(main.c和底层.c)添加到Keil
编译一下,发现5个报错:2个EEPROM函数和3个LED函数没有调用。以后使用到自然清除
移植完毕