目录

  • 添加芯片头文件
  • 两种程序开头写法
    • 使用 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. 本程序与开发板上的按键编号并不对应,本代码返回的按键编号总左至右、从上到下依次为 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

注:

  1. 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

注:

  1. 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();
}

温度传感器

注:

  1. 本程序只读取正整数。
// 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;
}

频率测量

注:

  1. 通过定时器0进行外部触发计数,定时器1进行1s计时,定时器1每触发一次中断通过计算定时器0的计数次数求得频率。


OSC 框表示时钟频率,因为1个机器周期等于12个时钟周期,所以那个 d 就等于12。下边 GATE
右边的那个门是一个非门电路,再右侧是一个或门,再往右是一个与门电路。

图上可以看出来,下边部分电路是控制了上边部分,那我们先来看下边是如何控制的,我们以定时器0为例。

  1. TR0 和下边或门电路的结果要进行与运算,TR0 如果是0的话,与运算完了肯定是0,所以如果要让定时器工作,那么 TR0 就必须置1。

  2. 这里的与门结果要想得到1,那么前面的或门出来的结果必须也得是1才行。在 GATE
    位为1的情况下,经过一个非门变成0,或门电路结果要想是1的话,那 INT0 即 P3.2 引脚必须是1的情况下,这个时候定时器才会工作,而
    INT0 引脚是0的情况下,定时器不工作,这就是 GATE 位的作用。

  3. 当 GATE 位为0的时候,经过一个非门会变成1,那么不管 INT0 引脚是什么电平,经过或门电路后都肯定是1,定时器就会工作。

  4. 要想让定时器工作,就是自动加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;}
}

注意事项

  1. 操纵时序结束后记得释放数据线:DAT = 1。
  2. IIC 总线:[0]应答 [1]非应答。
  3. IAP15芯片的WR/RD功能不是P36/P37引脚功能,故用P42/P44引脚代替。
  4. _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 开发板)总结相关推荐

  1. 蓝桥杯——单片机设计与开发初学者必备资料

    蓝桥杯--单片机设计与开发初学者必备资料 国信长天 大赛官方指定电子类比赛硬件提供方,可能大家只知道他们提供硬件,殊不知还有一些免费的视频讲解(只是老师可能说话带一点方言,嘻嘻),感兴趣的可以去看看, ...

  2. 蓝桥杯单片机组——榨干选手资源包(芯片数据手册)

    文章目录 前言 DS18B20 原理图 1-Wire协议简介 赛场技巧 DS1302 原理图 SPI协议简介 赛场技巧 AT24C02 原理图 IIC协议简介 赛场技巧 PCF8591 原理图 赛场技 ...

  3. 第jiu届蓝桥杯单片机省赛真题_第九届蓝桥杯单片机组省赛试题.pdf

    第九届蓝桥杯单片机组省赛试题 "彩灯控制器"的程序设计与调试 (70 分) 一.基本要求 1.1 使用CT107D 单片机竞赛板,完成"彩灯控制器"功能的程序设 ...

  4. 蓝桥杯单片机组——榨干选手资源包(STC)

    文章目录 前言 巧用STC STC生成定时器 STC配置定时器(定时器中断) 定时器 定时器中断 STC获取数码管码表 STC上升沿下降沿检测 其他 总结 目录 前言 笔者参加的是第十一届蓝桥杯的单片 ...

  5. 蓝桥杯单片机组——程序框架及客观题

    文章目录 前言 程序框架 main+中断 两段式代码结构 单片机运行流程 代码风格 客观题 总结 目录 前言 前面两篇主要是介绍了蓝桥省赛的一些参赛技巧,此篇主要是分享程序框架和一些客观题的链接. 程 ...

  6. 蓝桥杯单片机设计与开发_标准模板

    蓝桥杯单片机设计与开发_标准模板 一.前言 首先,这篇文章是笔者第一次在 CSDN 上写博文,较为生疏,读者若有任何意见,欢迎大家在评论区交流! 笔者目前为一名大二学生,参加了2021年蓝桥杯单片机设 ...

  7. 蓝桥杯单片机设计与开发题目分析与源码(智能门锁)

    蓝桥杯单片机设计与开发(智障门锁) 内附完整工程 代码仅供参考,如有建议疑问欢迎留言讨论 程序设计部分 智能门锁-任务指导书 开发环境 Keil5 Stc-isp 国兴天长开发板 任务分析 任务逻辑梳 ...

  8. 【蓝桥杯单片机组模块】4、按键模块

    微信搜索:ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复"代码"即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题.免费下载CSDN资源等 ...

  9. 【蓝桥杯单片机组】客观题(赛前必看)

    微信搜索:ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复"代码"即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题.免费下载CSDN资源等 ...

  10. 第十一届 蓝桥杯 单片机设计与开发项目 决赛

    第十一届 蓝桥杯 单片机设计与开发项目 决赛 题目 源码 赛题总结 1.界面切换 2.参数生效 3.LED显示 题目 源码 #include <STC15F2K60S2.H> #inclu ...

最新文章

  1. pytorch中T.RandomResizedCrop()等图像操作转换的效果
  2. 3月29日 如何在winform中加入动态系统时间
  3. 锡安赞歌 mp3下载
  4. 和朋友们一起探道一下CPA广告反作弊方面的技术,欢迎大家发表意见。
  5. Android Animation --ScaleAnimation
  6. IP计算机取证,计算机取证1资料.doc
  7. jwt token注销_退出登录时怎样实现JWT Token失效?
  8. SpringSecurity Filter顺序
  9. 【优化调度】基于matlab遗传算法求解公交车调度优化问题【含Matlab源码 040期】
  10. c语言中order函数,C语言order的用法
  11. 一篇文章教会你使用html+css3制作炫酷效果
  12. Springboot顺利达驾校预约管理系统毕业设计-附源码191748
  13. 使用递归方法查询所有分类(一)
  14. 阿里云云边一体容器架构创新论文被云计算顶会 ACM SoCC 录用
  15. 小时候 觉得爸爸就是天 无所不能~
  16. 微服务团队_为什么团队文化对于成功的微服务至关重要
  17. DS1307实时时钟RTC读取(STM32)记录
  18. 【PaperReading】使用limma、Glimma和edgeR对RNA-seq数据分析
  19. 复杂可编程逻辑器件CPLD
  20. python的网页解析器_Beautiful Soup常见的解析器

热门文章

  1. 校园失物招领系统,失物招领系统,校园失物招领管理系统毕设作品
  2. 第二章____一元函数微分学
  3. 文件系统(十一)—fuse内核实现
  4. nginx正向代理访问微信接口502错误, Unable to tunnel through proxy. Proxy returns \“HTTP/1.1 502 Bad Gateway\
  5. 为什么网络钓鱼攻击仍然有利可图----以及如何阻止它
  6. 如何安装操作系统?过程、图文。
  7. Mybatis——类型处理器TypeHandler
  8. latex论文排版初级应用
  9. 易语言 存储过程 mysql_在易语言中调用MS SQL SERVER数据库存储过程方法总结
  10. python百度地图标注,Python+百度地图实现地址多点标注--用上BMap了