文章目录[隐藏]
前言
上一次写博客仿佛是在一万年前。
不论你想从这篇博客中了解到什么,如果你是一个新手,请自己审查自己手里拿着的板子。我的单片机型号为STC89C52RC,如果你不是这个型号,那么本文所述可能将不适合你的开发。
另外,本文编写的目的是以STC89C52RC为参考,来纠正**《51单片机C语言程序设计教程》(作者王云·异步图书·人民邮电出版社)**中的一些表述和代码。
并不是说这本书说错了,而是这本书实在过于古老(自己看看那示例图片的浓浓XP风),已经不适合我这块生产于2021的开发板了
另外,这本书也不是专门为这块普中开发板所编写,因此难免会有出入。我并不想单纯地将这篇文章变成一个“纠偏”文章,而是希望通过这种“纠偏”能够使感兴趣的读者进一步深入了解单片机,也可以为笔者未来的复习提供很大的参考。
本文将持续更新
单片机上电
没想到吧,这本书说了一大堆,但是没告诉你怎么启动单片机[手动滑稽]
首先你需要找到你的单片机的USB口,普中开发板单片机使用MicroUSB而非TypeA,就是以前安卓手机用的接口。
这是一块STC89C52RD+开发板,不用担心,他们长得几乎一样。在本图左下角我们可以发现一个写着USB1的东西,这就是我说的microUSB接口了。而它的上方就是开关。
接入电脑后将会显示其驱动已经安装,此时你按动开关,单片机就会亮起。
STC-ISP冷启动
由于书本当中使用的STC-ISP冷启动和我们的普中单片机所配套的STC-ISP软件不同,本文在此说明一下我们的下载软件该怎么使用。当然,STC-ISP软件必须冷启动给我们带来了很大的不便,因此在本目末尾,将给出普中芯片的下载软件——PZ-ISP
当你打开STC-ISP的时候基本上都会弹出来这个提示,并且之后你所进入的界面也和书本所述不同。
事实上你也找不到STC89C52RC,你只能找到上图的东西。
但是没关系,基本操作是一样的。
你的串口号可以通过扫描来确定
如果你已经选好了单片机型号以及确定了端口号,你只需要点击下方的的打开文件,你就可以打开你烧录的HEX文件。
点击下载编程即可
注意,冷启动要求我们先设置好并点击下载后再打开单片机的power开关,否则程序下载将会失败!!!
经常点按单片机开关,一方面影响开关寿命,一方面频繁断电也容易影响单片机寿命。普中开发板另外配套了一款更加神级的软件,它允许我们进行“热启动”
普中自带的下载软件PZ-ISPlogo如下
普中PZ-ISP的软件的界面更加清爽,芯片类型也不会多到离谱
它具备STC-ISP的常用功能,当你插入单片机时,它将也会自动检测所有的可用串口。使用方法和STC-ISP相近,本文不再赘述。
PZ-ISP不需要冷启动,反之,你如果冷启动,反而会失败。请在开机状态下用PZ-ISP下载程序
点亮第一个LED实验代码修正
如果你认真的阅读了书本,那么点亮第一个LED的代码将会是这样:
#include<reg52.h>
sbit LED=P1^0;
void main(){
LED=0;
while(1);
}
当你认认真真搞完了代码,编译,烧录后,你发现单片机根本不理你。试了很多次,然而一点办法也没有。你可能觉得使单片机坏了,而事实并不是这样。
书本在前文已经讲了发光二极管的原理,单片机通过改变引脚电平来控制发光二极管两端的电位,因此我们可以首先考虑是否是引脚的问题。
拿到开发板,首先查看技术文档是一个好习惯,技术文档描述了手中开发板的性能和特点。而网络上的意见未必适用与你的情况
如图所示,这是8个共阳极发光二极管。这里可能会有同学被单片机的标识误导。如下方图片所示,在区域5中同时标有LED模块和88点阵,而实际上88点阵是区域4。
另外 ,在LED模块示意图中,我们知道LED模块阴极实际上连接着单片机P2引脚群而不是P1引脚群。(假设忽略锁存器RP9和RP10,因为锁存器在使用时都是可以看作导通的)
锁存器可以看成是一种大型的RS触发器(基本触发器),它也具有保持态。书本P27举例了关于锁存器74HC573的例子,这里不再赘述。
为了解决LED无法点亮的问题,我们只需要将所控制的引脚代码修改一下即可。
#include<reg52.h>
sbit LED=P2^0;
void main(){
LED=0;
while(1);
}
P2^0就是指P2引脚群的第一个引脚,我们只需更改一个引脚名称,就可以是程序正确起来。
理解GPIO引脚的新方式
我们的单片机有三组GPIO引脚,P0,P1,P2,P3.
通过查看<reg52.h>头文件,我们可以知道这四组引脚的寄存器地址
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
每一个引脚组间均留出了10个空余地址,再让我们反过来思考在C51中一个让初学者都感到不解的奇怪写法——P2^1
如果不去做深入思考,我们只能知道,它想表达的是在P2引脚群中的第2个引脚的意思(注意P2^0才是第一个引脚)
可是我们根据C语言的常识,我们知道 ^符号是按位异或的意思,而在<reg52.h>头文件中,我们并没有发现这个符号以何种方式进行了运算符重载,也就是说,这里的按位异或符号还真的是按位异或的意思!!
根据我们在**<reg52.h>头文件中所看到的每一组GPIO引脚所在的首地址**,我们对代码LED=P2^0
做按位异或运算。所以我们知道LED=0xA0
这刚好就是P2引脚群的首地址!
那么,P2^1呢?
如我们所见,恰是0xA1!!
也就是首地址的下一个地址。
若地址都是连续的,我们不妨使用十六进制的地址信息直接对P2引脚群进行统一赋值,如
0x7F 对应 0111 1111 点亮D8灯
0xBF 对应 1011 1111 点亮D7灯
**为什么引脚信号为0才会点亮呢?**因为我们使用的是共阳极发光二极管!所以GPIO引脚低电平点亮,高电平熄灭。
如果你已经理解了,那么不妨看看如下代码:
#include<reg52.h>
unsigned int i=0;
void main(){
while(1){
P2=0xF0;
}
}
它简单地实现了让四个灯保持全亮,而免去了挨个打P2^X的麻烦
运用这样的原理,我们可以使用延时函数结合巧妙的移位操作写出流水灯程序
#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
//相当于将int写成u16
typedef unsigned char u8;
#define LED_PORT P2 //使用宏定义P2端口
void delay_10us(u16 ten_us){ //这是一个简单的延时函数
while(ten_us--);
}
void main(){
u8 i=0; //可以去查看上面的typedef
LED_PORT=~0x01;
delay_10us(50000);
while(1)
{
for(i=0;i<8;i++){
LED_PORT=~(0x01<<i); //将1右移i位,然后取反将结果赋值到LED_PORT
delay_10us(50000);
}
}
}
版权声明:本文为CSDN博主「RealMartinX」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Martisum/article/details/122552395
暂无评论