蓝桥杯单片机组(CT107D 开发板)总结
目录
- 添加芯片头文件
- 两种程序开头写法
- 使用 reg52.h 开头的程序
- 使用 stc15f2k60s2.h 开头的程序
- 上电初始化
- 软件延时(ms)
- 数码管显示
- 定时器初始化
- T0
- T1
- T2
- 外部中断初始化
- INT0
- INT1
- 矩阵键盘扫描
- EEPROM
- 单字节读写
- 多字节读写
- AD/DA
- ADC
- DAC
- 温度传感器
- 时钟芯片
- 串口
- 超声波测距模块
- 频率测量
- PWM
- 注意事项
- 推荐阅读
添加芯片头文件
keil c51默认并没有携带STC芯片的固件库,添加固件库的步骤如下:
1、在下载软件右侧tab界面选择“keil仿真设置”标签,并点击下方红框框出的按钮(“添加型号和头文件…到Keil中”按钮)进行添加。如图1所示。
2、选择添加固件库的路径,如图2所示。务必注意要选择Keil软件的安装根目录,选择好之后点击“确定”。
当我们再打开keil软件新建工程时,就可以看到我们所需要的芯片型号了。如图3所示。
两种程序开头写法
使用 reg52.h 开头的程序
#include “reg52.h”sfr P4 = 0xc0; // reg52.h 中没有定义 P4 寄存器故自己定义
sbit P3_6 = P4^2; // 位定义用 P3_6 在程序中替换 P4^2的功能
sbit P3_7 = P4^4; // 同上
使用 stc15f2k60s2.h 开头的程序
#include “stc15f2k60s2.h” // 该文件已定义 P4 寄存器故无需重复定义sbit P3_6 = P4^2; // 位定义用 P3_6 在程序中替换 P4^2 的功能
sbit P3_7 = P4^4; // 同上
上电初始化
// 通过译码器选择对应的锁存器
void select(uchar num)
{switch (num){case 4: P2 = (P2 & 0x1f) | 0x80; break;case 5: P2 = (P2 & 0x1f) | 0xa0; break;case 6: P2 = (P2 & 0x1f) | 0xc0; break;case 7: P2 = (P2 & 0x1f) | 0xe0; break;default: P2 &= 0x1f; break;}
}void init()
{// 关闭蜂鸣器、LED灯、数码管select(5); // 关闭蜂鸣器P0 = 0x00;select(4); // 关闭LED灯P0 = 0xff;select(6); // 选中全部数码管P0 = 0xff;select(7); // 关闭数码管P0 = 0xff;select(0); // 锁存
}
软件延时(ms)
// Delayms
void delayms(uint time)
{uint i, j;for (i = time; i > 0; i--)for (j = 845; j > 0; j--);
}
数码管显示
uchar numChar[] = {0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8, 0X80, 0X90};
// 数码管
void shumaguan(uchar wei, uchar num)
{select(7); // 关闭数码管P0 = 0xff;select(0);P0 = 0x00;select(6); // 位选P0 = 0x80 >> wei; // [0x80]从左至右 [0x01] 从右至左select(0);P0 = 0xff;select(7);P0 = numChar[num];select(0);Delay3ms(); // 延时 3ms
}
定时器初始化
T0
void Timer0Init(void) // 10 毫秒 @11.0592MHz
{AUXR &= 0x7F; // 定时器时钟 12T 模式TMOD &= 0xF0; // 设置定时器模式TL0 = 0x00; // 设置定时初值TH0 = 0xDC; // 设置定时初值TF0 = 0; // 清除 TF0 标志TR0 = 1; // 定时器 0 开始计时EA = 1;ET0 = 1;
}
T1
void Timer1Init(void) // 10 毫秒 @11.0592MHz
{AUXR &= 0xBF; // 定时器时钟 12T 模式TMOD &= 0x0F; // 设置定时器模式TL1 = 0x00; // 设置定时初值TH1 = 0xDC; // 设置定时初值TF1 = 0; // 清除 TF1 标志TR1 = 1; // 定时器 1 开始计时EA = 1;ET1 = 1;
}
T2
void Timer2Init(void) // 10 毫秒 @11.0592MHz
{AUXR &= 0xFB; // 定时器时钟 12T 模式T2L = 0x00; // 设置定时初值T2H = 0xDC; // 设置定时初值AUXR |= 0x10; // 定时器 2 开始计时EA = 1;IE2 |= 0x04;
}
外部中断初始化
INT0
void initInter0()
{IT0 = 1; // 中断触发方式:[0]低电平触发 [1]下沿触发EX0 = 1; // 打开外部中断EA = 1; // 开启总中断
}
INT1
void initInter1()
{IT1 = 1; // 中断触发方式:[0]低电平触发 [1]下沿触发EX1 = 1; // 打开外部中断EA = 1; // 开启总中断
}
矩阵键盘扫描
注:
- 本程序与开发板上的按键编号并不对应,本代码返回的按键编号总左至右、从上到下依次为 1~16。
1 | ~ | 4 |
~ | … | ~ |
11 | ~ | 16 |
// 矩阵键盘
// IAP15 芯片的 WR/RD 功能不是 P36/P37 引脚功能,故用 P42/P44 引脚代替
// 即:P3^6 => P42 P3^7 => P44
uchar keyScan()
{uchar keyValue = 0;// 键盘初始化P3 = 0x0f; P42 = 0; P44 = 0;// 键盘扫描if (P3 != 0x0f){delayms(10); // 消抖if (P3 != 0x0f){switch (P3){case 0x07: keyValue = 13;break;case 0x0b: keyValue = 9; break;case 0x0d: keyValue = 5; break;case 0x0e: keyValue = 1; break;default: return 0;}// 键盘翻转P3 = 0xf0; P42 = 1; P44 = 1;// 扫描if (!P34) keyValue += 3;else if (!P35) keyValue += 2;else if (!P42) keyValue += 1;else if (!P44) keyValue += 0;else return 0;// 等待按键抬起while (P3 != 0xf0);while (!P42);while (!P44);}}return keyValue; // 返回按键值,如无按键按下则返回 0
}
EEPROM
注:
- AT24C02 地址 0xA0。
单字节读写
// EEPROM 设备地址 0xA0
void writeByte(uchar addr, uchar byt)
{IIC_Start();IIC_SendByte(devAddr);IIC_WaitAck();IIC_SendByte(addr);IIC_WaitAck();IIC_SendByte(byt);IIC_WaitAck();IIC_Stop();
}uchar readByte(uchar addr)
{uchar dat;IIC_Start();IIC_SendByte(devAddr);IIC_WaitAck();IIC_SendByte(addr);IIC_WaitAck();IIC_Start();IIC_SendByte(devAddr | 0x01);IIC_WaitAck();dat = IIC_RecByte();IIC_Ack(0);IIC_Stop();return dat;
}
多字节读写
// AT24C02 共 256 个字节 分为 8 页 共 32 页
// 页写入
void write(uchar addr, uchar len, uchar *arr)
{while (len > 0){while (1){IIC_Start();IIC_SendByte(devAddr);if (IIC_WaitAck()) break;}IIC_SendByte(addr);IIC_WaitAck();while (len > 0){IIC_SendByte(*arr++);IIC_WaitAck();len--;addr++;// 判断是否达到页边界if ((addr & 0x07) == 0) break;}IIC_Stop();}
}void read(uchar addr, uchar len, uchar *arr)
{while (1){IIC_Start();IIC_SendByte(devAddr);if (IIC_WaitAck()) break;}IIC_SendByte(addr);IIC_WaitAck();IIC_Start();IIC_SendByte(devAddr | 0x01);IIC_WaitAck();while (--len){*arr++ = IIC_RecByte();IIC_Ack(1);}*arr = IIC_RecByte();IIC_Ack(0);IIC_Stop();
}
AD/DA
注:
- PCF8951 地址 0x90。
ADC
// [chl]选择通道
uchar ADC(uchar chl)
{uchar value;while (1) // 等待设备应答{IIC_Start();IIC_SendByte(0x90);if (IIC_WaitAck()) break;}IIC_SendByte(chl);IIC_WaitAck();IIC_Stop();IIC_Start();IIC_SendByte(0x91);IIC_WaitAck();value = IIC_RecByte();IIC_Ack(0);IIC_Stop();return value; // 需转换为电压值
}
DAC
void DAC(uchar value) // 输入值需要转换
{while (1){IIC_Start();IIC_SendByte(devAddr);if (IIC_WaitAck()) break;}IIC_SendByte(0x40);IIC_WaitAck();IIC_SendByte(value);IIC_WaitAck();IIC_Stop();
}
温度传感器
注:
- 本程序只读取正整数。
// DS18B20
// XXXX YYYY YYYY ZZZZ
// [X]正负(0-正 1-负) [Y]温度整数值 [Z]温度小数值(Z * 0.0625)
uchar Temper_Read()
{uchar temp, Tl, Th;Init_DS18B20(); // DS18B20 初始化Write_DS18B20(0xcc); // 跳过 ROM 的字节命令Write_DS18B20(0x44); // 开始转换指令Delay_OneWire(200); // 延时一段时间Init_DS18B20(); // DS18B20 初始化Write_DS18B20(0xcc); // 跳过 ROM 的字节命令Write_DS18B20(0xbe); // 读取指令Tl=Read_DS18B20(); // 读低八位Th=Read_DS18B20(); // 读高八位temp = (Th << 4) | (Tl >> 4); // 只取整数return temp;
}
时钟芯片
// DS1302
writeDS1302(0x8E, 0); // 关闭写保护
// 突发模式:必须一次性读写全部 8 个字节
// [0xBF]读 [0xBE]写
writeByte(0xBF); // 突发读
writeByte(0xBE); // 突发写
串口
注:波特率为 9600bps
// UART
void UartInit(void) //9600bps@11.0592MHz
{SCON = 0x50; // 8位数据,可变波特率AUXR |= 0x40; // 定时器1时钟为Fosc,即1TAUXR &= 0xFE; // 串口1选择定时器1为波特率发生器TMOD &= 0x0F; // 设定定时器1为16位自动重装方式TL1 = 0xE0; // 设定定时初值TH1 = 0xFE; // 设定定时初值ET1 = 0; // 禁止定时器1中断TR1 = 1; // 启动定时器1ES = 1; // 允许串口中断EA = 1; // 开启总中断
}void UARTInter() interrupt 4
{if (TI == 1){TI = 0; // 手动清除中断标志}if (RI == 1){RI = 0; // 手动清除中断标志SBUF = SBUF + 1;}
}
超声波测距模块
// 超声波测距
#define nop() {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
uint echo()
{uchar i;uint distance;initTimer();// 起始信号out = 0;for (i = 0; i < 16; i++){out = ~out;nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();}// 接收信号while (!in);TR0 = 1;while ((in == 1) && (TF0 == 0)); // 信号结束或计时器计满TR0 = 0;// 计算if (TF0) // 计时器计满,超出测量范围{distance = 0;TF0 = 0;}else {distance = (uint) (TH0 << 8) | TL0;distance *= 0.017 * 1.085; // 单位 cm (1.085 为误差补偿)}return distance;
}
频率测量
注:
- 通过定时器0进行外部触发计数,定时器1进行1s计时,定时器1每触发一次中断通过计算定时器0的计数次数求得频率。
OSC 框表示时钟频率,因为1个机器周期等于12个时钟周期,所以那个 d 就等于12。下边 GATE
右边的那个门是一个非门电路,再右侧是一个或门,再往右是一个与门电路。图上可以看出来,下边部分电路是控制了上边部分,那我们先来看下边是如何控制的,我们以定时器0为例。
TR0 和下边或门电路的结果要进行与运算,TR0 如果是0的话,与运算完了肯定是0,所以如果要让定时器工作,那么 TR0 就必须置1。
这里的与门结果要想得到1,那么前面的或门出来的结果必须也得是1才行。在 GATE
位为1的情况下,经过一个非门变成0,或门电路结果要想是1的话,那 INT0 即 P3.2 引脚必须是1的情况下,这个时候定时器才会工作,而
INT0 引脚是0的情况下,定时器不工作,这就是 GATE 位的作用。当 GATE 位为0的时候,经过一个非门会变成1,那么不管 INT0 引脚是什么电平,经过或门电路后都肯定是1,定时器就会工作。
要想让定时器工作,就是自动加1,从图上看有两种方式,第一种方式是那个开关打到上边的箭头,就是 C/T =0 的时候,一个机器周期 TL
就会加1一次,当开关打到下边的箭头,即 C/T =1 的时候,T0 引脚即 P3.4 引脚来一个脉冲,TL 就加1一次,这也就是计数器功能。
极客学院_5.3 单片机定时器的寄存器:http://wiki.jikexueyuan.com/project/mcu-tutorial-one/timer-register.html
// 频率测量 NE555
uint fre;
uchar count = 0;void initNE555Fre()
{TMOD = 0x15; // T1:定时器 T0:计数器TH0 = TL0 = 0; // 计数清零TL1 = 0x00; // 设置定时初值TH1 = 0x4C; // 设置定时初值TF0 = TF1 = 0;TR0 = TR1 = 1;ET1 = 1;EA = 1;
}void timer() interrupt 3
{TL1 = 0x00; // 设置重装TH1 = 0x4C; // 设置重装if (count++ == 20){count = 0;fre = (uint) (TH0 << 8) | TL0;TL0 = TH0 = 0;}
}
PWM
sbit PWM = P1^0; // PWM 输出口uchar HTH, HTL; // 高电平持续时间
uchar LTH, LTL; // 低电平持续时间
// 高电平计数, 低电平计数, 定时计数
uchar HC, LC, TC;
bit PWMF = 1; // PWM 标志void changePWM(uint fre, uchar dc)
{float HTime, LTime;float time = 1090000.0 / fre; // 周期 = 10^6毫秒 / 频率(fre)LTime = (time * dc / 100) * 11059200 / 12 / 1000000;HTime = (time - LTime) * 11059200 / 12 / 1000000;if (dc <= 0 || dc >= 100 || fre <= 0) {TC = 255;if (dc <= 0) PWM = 0;else PWM = 1;return;}// 计数计算if (65536 < HTime) HC = HTime / 65536;else HC = 0;TH0 = HTH = (65536 - HTime) / 256;TL0 = HTL = (uint) (65536 - HTime) % 256;if (65536 < LTime) LC = LTime / 65536;else LC = 0;LTH = (65536 - LTime) / 256;LTL = (uint) (65536 - LTime) % 256;// 初始化TH0 = TL0 = 0;TC = LC;if (HC != 0)TC = HC;
}void startPWM(uint fre, uchar dc)
{// PWM 初始化PWM = 1;TC = HC = LC = 0;// 定时器初始化TMOD &= 0xf0;TMOD |= 0x01;changePWM(fre, dc);EA = 1;TF0 = 0;ET0 = 1;TR0 = 1;
}void stopPWM()
{TR0 = 0;PWM = 1;
}void PWMTimer() interrupt 1
{// 当占空比为 0 或 100 时保持电瓶不变if (TC == 255) return;if (!TC--){if (PWM){TH0 = HTH;TL0 = HTL;TC = HC;}else {TH0 = LTH;TL0 = LTL;TC = LC;}PWM = ~PWM;}
}
注意事项
- 操纵时序结束后记得释放数据线:DAT = 1。
- IIC 总线:[0]应答 [1]非应答。
- IAP15芯片的WR/RD功能不是P36/P37引脚功能,故用P42/P44引脚代替。
- _nop_() 函数所在头文件为 intrins.h。
推荐阅读
单片机中文网:http://c.biancheng.net/cpp/danpianji/
单片机入门基础教程: https://wiki.jikexueyuan.com/list/microcontrollers/
Bkoak 博客:http://www.bkoak.com/
EEPW 论坛:http://forum.eepw.com.cn/thread/302835/1
蓝桥杯单片机组(CT107D 开发板)总结相关推荐
- 蓝桥杯——单片机设计与开发初学者必备资料
蓝桥杯--单片机设计与开发初学者必备资料 国信长天 大赛官方指定电子类比赛硬件提供方,可能大家只知道他们提供硬件,殊不知还有一些免费的视频讲解(只是老师可能说话带一点方言,嘻嘻),感兴趣的可以去看看, ...
- 蓝桥杯单片机组——榨干选手资源包(芯片数据手册)
文章目录 前言 DS18B20 原理图 1-Wire协议简介 赛场技巧 DS1302 原理图 SPI协议简介 赛场技巧 AT24C02 原理图 IIC协议简介 赛场技巧 PCF8591 原理图 赛场技 ...
- 第jiu届蓝桥杯单片机省赛真题_第九届蓝桥杯单片机组省赛试题.pdf
第九届蓝桥杯单片机组省赛试题 "彩灯控制器"的程序设计与调试 (70 分) 一.基本要求 1.1 使用CT107D 单片机竞赛板,完成"彩灯控制器"功能的程序设 ...
- 蓝桥杯单片机组——榨干选手资源包(STC)
文章目录 前言 巧用STC STC生成定时器 STC配置定时器(定时器中断) 定时器 定时器中断 STC获取数码管码表 STC上升沿下降沿检测 其他 总结 目录 前言 笔者参加的是第十一届蓝桥杯的单片 ...
- 蓝桥杯单片机组——程序框架及客观题
文章目录 前言 程序框架 main+中断 两段式代码结构 单片机运行流程 代码风格 客观题 总结 目录 前言 前面两篇主要是介绍了蓝桥省赛的一些参赛技巧,此篇主要是分享程序框架和一些客观题的链接. 程 ...
- 蓝桥杯单片机设计与开发_标准模板
蓝桥杯单片机设计与开发_标准模板 一.前言 首先,这篇文章是笔者第一次在 CSDN 上写博文,较为生疏,读者若有任何意见,欢迎大家在评论区交流! 笔者目前为一名大二学生,参加了2021年蓝桥杯单片机设 ...
- 蓝桥杯单片机设计与开发题目分析与源码(智能门锁)
蓝桥杯单片机设计与开发(智障门锁) 内附完整工程 代码仅供参考,如有建议疑问欢迎留言讨论 程序设计部分 智能门锁-任务指导书 开发环境 Keil5 Stc-isp 国兴天长开发板 任务分析 任务逻辑梳 ...
- 【蓝桥杯单片机组模块】4、按键模块
微信搜索:ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复"代码"即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题.免费下载CSDN资源等 ...
- 【蓝桥杯单片机组】客观题(赛前必看)
微信搜索:ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复"代码"即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题.免费下载CSDN资源等 ...
- 第十一届 蓝桥杯 单片机设计与开发项目 决赛
第十一届 蓝桥杯 单片机设计与开发项目 决赛 题目 源码 赛题总结 1.界面切换 2.参数生效 3.LED显示 题目 源码 #include <STC15F2K60S2.H> #inclu ...
最新文章
- pytorch中T.RandomResizedCrop()等图像操作转换的效果
- 3月29日 如何在winform中加入动态系统时间
- 锡安赞歌 mp3下载
- 和朋友们一起探道一下CPA广告反作弊方面的技术,欢迎大家发表意见。
- Android Animation --ScaleAnimation
- IP计算机取证,计算机取证1资料.doc
- jwt token注销_退出登录时怎样实现JWT Token失效?
- SpringSecurity Filter顺序
- 【优化调度】基于matlab遗传算法求解公交车调度优化问题【含Matlab源码 040期】
- c语言中order函数,C语言order的用法
- 一篇文章教会你使用html+css3制作炫酷效果
- Springboot顺利达驾校预约管理系统毕业设计-附源码191748
- 使用递归方法查询所有分类(一)
- 阿里云云边一体容器架构创新论文被云计算顶会 ACM SoCC 录用
- 小时候
觉得爸爸就是天
无所不能~
- 微服务团队_为什么团队文化对于成功的微服务至关重要
- DS1307实时时钟RTC读取(STM32)记录
- 【PaperReading】使用limma、Glimma和edgeR对RNA-seq数据分析
- 复杂可编程逻辑器件CPLD
- python的网页解析器_Beautiful Soup常见的解析器
热门文章
- 校园失物招领系统,失物招领系统,校园失物招领管理系统毕设作品
- 第二章____一元函数微分学
- 文件系统(十一)—fuse内核实现
- nginx正向代理访问微信接口502错误, Unable to tunnel through proxy. Proxy returns \“HTTP/1.1 502 Bad Gateway\
- 为什么网络钓鱼攻击仍然有利可图----以及如何阻止它
- 如何安装操作系统?过程、图文。
- Mybatis——类型处理器TypeHandler
- latex论文排版初级应用
- 易语言 存储过程 mysql_在易语言中调用MS SQL SERVER数据库存储过程方法总结
- python百度地图标注,Python+百度地图实现地址多点标注--用上BMap了