单片机入门学习2
51单片机入门学习记录(2)
教程:江科协
51单片机 Keil C语言
目录:
[LED点阵屏](#1.25 LED点阵屏)
1.25 LED点阵屏
过年好 单片机的学习停了一个星期 刚刚看到弹幕一句话:都学到这了 怎么能半途而废呢
啊啊啊啊可是才P21 一共有P38 才学到一半啊啊啊啊啊啊啊啊啊啊啊!
8*8个LED组成
因为引脚共用 所以仍需采取逐行逐列扫描 扫描过快 显示就可以一起
开发板引脚对应关系
移位寄存器 74HC595
74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。
- sfr(special function register):特殊功能寄存器声明
例:sfr P0 = 0x80;
声明P0口寄存器,物理地址为0x80
- sbit(special bit):特殊位声明
例:sbit P0_1 = 0x81; 或 sbit P0_1 = P0^1;
声明P0寄存器的第1位
可位寻址/不可位寻址:每8个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若要只操作其中一位而不影响其它位时,可用“&=”、“|=”、“^=”的方法进行位操作
看到文件中 同一个地址有不同的名称?去搜了一下
贴一个看到的博客
字节地址和位地址的区别:
一、位地址是字节地址中的某一位,在RAM 中,位地址20H是字节地址24H的最低位。
二、字节地址20H有8个位地址:从00H—07H,所以在用汇编去编程的时候,需要注意操作的地址是位地址还是字节地址。
三、把数据存放在含有位地址的字节地址中相连时,可以在程序中去改变这个数据的某一位,所以字节地址中可以存放8个位变量。
四、在用汇编去编程的时候,需要注意操作的地址是位地址还是字节地址。
五、把数据存放在含有位地址的字节地址中时,可以在程序中去改变这个数据的某一位,字节地址中可以存放8个位变量
六、位寻址取值范围就是0和1,字节寻址是0-255
LED点阵屏显示图片
给一些位置进行重新申明
但RCLK
在头文件里已经定义过了 这些只是相当于外号 并没有什么关系 改名~
- 定义一个函数用来把Byte写入八个引脚
首先要把数据赋值给SER:取Byte的最高位 SER = Byte&0x80
注意:把一个数赋值给一个位,原则是:非0即1,即这个数不是0 则赋给前面1 ,也就是这里0x80
非0 则赋给SER
1,当然也可以用if原则
-
给SELK时钟高电平让其移位
首先上电后 SCK全是高电平 所以要先置0
测试74HC585芯片
1 |
|
hh发现我的板子没有74H595的LED灯(ˉ▽ˉ;)…😶
按照弹幕的说法可以给P0=0x00一个初值,此时LED点阵屏亮了一半,测试595芯片ok
对点阵屏进行操作,引脚关系详见
测试:以第一列为例
1 |
|
类似于数码管,如果多列显示未消抖延迟的话,会类似数码管(段选->位选->段选->位选->段选···会造成错乱),故需要Delay
函数
使得(段选->位选**->延时->位清零**->段选->位选->段选)
1 |
|
测试对角线显示:
1 |
|
画笑脸
1 |
|
LED点阵屏显示动画
先模块化一下
显示动画可以先存一个数组 然后逐个显示(从左往右)
up主给了一个字模提取很便捷的软件
MatrixLED.h
1 |
|
MatrixLED.c
1 |
|
main.c
1 |
|
一般数组是会放在ram里会很浪费 要给他放在flash里unsigned char code Animation
1.27 DS1302实时时钟
时钟显示+调节时间
RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片
定时器的时钟会占用CPU时间且精度不高,断电就会清零
实时时钟内部带一个备用电池,断电后会提供能量
内部结构图
内部RTC寄存器
WP:write protect,置1的话写入无效
目标:在寄存器写入单片机的数据、在寄存器读出时钟芯片(DS1302)的数据
时序定义
上升沿时地址,下降沿是数据?
写入数据:
先把CE置1,发一个命令字(Command Byte)决定读写位置与方式,IO口写入最低位决定是读还是写(最开始),SCLK一个上升沿读入数据,归零后再给一个上升沿读取新的数据,依次循环八位···操作完后再把CE置0
读取数据:
按照上面的依然需要八个上升沿决定读写位置和方式,W给1单片机接收到命令值,紧跟着时钟的下降沿开始读出适中的数据
1.28 DS1302实时时钟&可调时钟
实时时钟
先对三个端口进行定义(方便一点)
1 |
|
^是位选,_是已经定义的, ^其实是PIO口的地址
模拟时序
操作前要先初始化,CE默认是0,但单片机上电时默认都是1
1 |
|
单字节写
先高电平使能,后从低到高取值
1 |
|
单字节读取
如果按照上面的话在循环结束后是已经完整地进行了八个上下沿,第一个数据已经被读取了
读取是要比写入少一个脉冲的 因为最后一次是立马读出数据的,所以要更换顺序,使得第一次循环结束后所在的位置左边都是与写入有关的
测试
显示了255?
看到弹幕说是有写入保护,要在LCD_Init();
后写DS1302_WriteByte(0x8E,0x00);
,但是好像也没有用欸
和up主的源代码对比发现少了一个DS1302_IO=0; //读取后将IO设置为0,否则读出的数据会出错
正常了但是很不稳定 但是不怎么懂原理 这一节的读取好不容易 不太理解 到时候再看一下(要加上接触芯片保护的)
1 |
|
但是到009后直接变成了016
原因:DS1302内部的寄存器是以BDC码进行存储的
9为0000 1001 10为 0001 0000 16为0001 0110
解决方法:以16进制显示LCD_ShowHexNum(2,1,Second,3);
,或者LCD_ShowNum(2,1,Second/16*10+Second%16,3);
1 |
|
秒分钟小时对应的参考如下
为了每次可以不用查表,可以配置一个表格
DS1302.c
1 |
|
main.c
1 |
|
好难···有很多细节不是很理解···只能大体知道点···
2.1 蜂鸣器
介绍原理
按驱动方式分类:
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定
无源蜂鸣器:需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音
(本节内用单片机提供方波脉,交流振荡发声,电能转化为机械能,但蜂鸣器不能长时间一直通电,容易造成烧毁)
单片机的I/O口不能直接驱动蜂鸣器,必须要过ULN2003芯片
ULN2003芯片(一边用于五线四相步进电机的驱动)
所以只需控制P15口就可以产生振动频率输出01来控制蜂鸣器(好像有说新版变成了P25口,到时候编程的时候测试一下)
注意:单片机上电的时候默认是高电平,P15默认取反为0,故OUT5为0,即默认会有电流,蜂鸣器会响一下,且始终通电流
播放音乐的参数:音高、时长
根据频率值控制定时器产生相应频率的计时,从而控制中断控制IO口的反转
频率的关系,可以计算定时器的重装值:
注意:
-
一个机器周期=12个晶振周期
-
翻转IO口控制频率时,翻转两次才是一个周期
-
所以翻转的时间时1/2
-
重装载值将高八位取出放到TH0,第八位放在TL0,再控制定时器中断
播放提示音
目的:按键松开瞬间给一个按键提示音
注意:
-
要把数码管模块代码中清零部分删除(此次是静态显示)
-
蜂鸣器标准频率是1000hz
up主最后是用了默认的标准频率,在他的基础上我修改了为可以自己设定频率(可选参数)和延长的时间
不过现在才发现,用C语言定义带默认参数/不定参数的函数不像C++那样便捷
参考了博客要写些代码···嗯好麻烦好麻烦的···
所以还是简单些说明,如果不自定义频率的参数就要传入0吧···下次有时间写一下cpp文件试试?(大概率是不会去写的hh)
2.3 蜂鸣器
感觉越临近开学越不好好学了,难道是开学焦虑综合征(fp)应该又是太多东西堆积所以顾不过来的时候,就好想摆烂
真的感觉在多线程前会非常力不从心且一件都很难做好,还会搞得身心很疲惫
用板子试了一下 确实是P2^5
main.c
1 |
|
Buzzer.c
1 |
|
音乐
受不鸟了听不下去了,直接copy了…记录一下听到了32:20,如果下次需要的话再继续看…
1 |
|