刚开始代码单纯的使用0和1,代码的可读性不高
所以使用define来定义
define的作用就是定义这些本身没有意义的数据,给它附上了一个属于有自己意义的名字
查询法除了查询动作状态,还会查询按键位
振动传感器控制灯
通过掌握的LED来了解振动传感器是怎么回事
···如何知道发生振动
···振动后的信号表现是什么
···振动传感器控制灯
/*中文注释来帮助开发思路*/
void main()
{
//循环,程序不能结束,这样才能不断检测,如果不添加循环,有可能出现问题
//如果发生了振动,那么对应的引脚为低电平
//灯亮
//否则
//什么事都不做,或者灯灭掉
}
产生振动,输出低电平,绿色指示灯亮
类似人使用的开关一样,单片机使用的开关是
在和89c52的连接过程中, GND接GND VCC接VCC IN接口52开发板的某个I/O口
IN连进来的作用是什么呢?
默认情况下COM口和NO口我们叫做常开,IN这个引脚没有收到一个低电平的时候,COM口和NO口是一个断开的状态
当收到一个低电平的时候,闭合在NC常闭端的贴片转向常开口端,导致公共端COM和常开端接通,导致串联电路联通,负载(灯)等就会亮
(当COM口和NO口接通的时候,绿色的灯就会亮)
遥控发送接收443M
~~遥控被按下之后怎么接受
~~接收后的信号表现又是什么
~~遥控控制LED
#include "reg52.h"
sbit switcher = P1^1;// switcher: 开关
sbit BP1 = P3^1;// B按键
sbit A = P3^2;// A按键
void main()
{
//查询,是否发生振动
while(1){
if(A == 1){
//当发生震动的时候,导通继电器,给继电器IN一个低电平
switcher = 0;//给一个低电平
}
if(BP1 ==1){
switcher = 1;
}
}
}
电动车简易报警装置
#include "reg52.h"
#include <intrins.h>
#define J_ON 0
#define J_OFF 1
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//设置针脚
//振动传感装置
sbit vibrate = P1^3;
//继电器装置
sbit switcher = P1^0; //switcher :开关
//报警器
//遥控控制开关
sbit D0_ON = P1^1;
sbit D1_OFF = P1^2;
void main()
{
//判断一个按键标志位
int mark = J_OFF;
while(1)
{
//如果A按键被按下,则认为进入警报模式
if(D0_ON == 1)
{
switcher = 0;
//长响两秒,进入警报模式
Delay2000ms();
switcher = 1;
mark = J_ON;
}
//如果B按键被按下,则认为退出警报模式
if(D1_OFF == 1)
{
switcher = 0;
//长响一秒,退出警报模式
Delay500ms();
switcher = 1;
mark = J_OFF;
}
//在警报模式的状态下,发生震动,则警报响,不震动,则警报不响
if(mark == 0)
{
//产生震动,输出低电平,绿色指示灯亮 所以是0
if(vibrate == 0)
{
Delay500ms();
//喇叭响,给继电器低电平,导通
switcher = 0;
Delay2000ms();
Delay2000ms();
Delay2000ms();
switcher = 1;
/*
但是此处有bug,必须采用中断的方式,才能处理
这是一个while死循环, 如果有震动,会一直响,此时按B按钮也没用
中断的意思就是,终止输出这件事情
*/
}else if(vibrate ==1 )
{
//喇叭不响,给继电器高电平,不导通
switcher = 1;
}
}
}
}
c语言中的定时器和计数器都是同一个硬件电路支持的,通过寄存器配置不同,就可以将他当做定时器或者计时器使用。
确切的说,定时器和计数器区别是致使他们背后的技术存储器
~定时器和计数器,电路一样
~定时或计数的本质就是让单片机某个部件数数
~当定时器用的时候,靠内部震荡电路数数
~当计时器用的时候,数外面的信号,读取针脚的数据
定时器怎么定时
定时器的本质原理:每经过一个机器周期,就加一
~晶振,是各种电子产品里面必不可少的频率元器件,元器件上面会写
~时钟周期
时钟周期,也成为振荡周期,定义为时钟频率的倒数
时钟周期是计算机中最基本的最小的时间单位。在一个时钟周期内CPU仅完成一个最基本的动作,时钟周期是一个时间的量,更小的时钟周期就意味着更高的工作频率
~机器周期
也成为CPU周期,一个机器周期一般为12个时钟周期
加一经过了多长时间
当晶振的频率是11.0592MHz的时候,等于11059.2KHz = 11059200Hz
机器周期 = 12 * 时钟周期 = 12 * (1/时钟频率)秒 = 12/时钟频率 秒 =12 000 000/11 029 200微秒
=1.085微秒
~在哪里加一,最大计数时间,也就是爆表了能计算多长
在TL和TH寄存器中加1,默认是从0开始数数,最多能数65532下(2的16次方),累计计时71ms
~那如何能计算出10ms呢?
数10ms需要9216下,
不让它从0开始数,让他从65532-9216 = 56320开始数数(16进制表示为0xDC00),
为什么用16进制表示呢?因为有TH和TL,00放在TL,DC放在TH(因为要拆分)
这样TL0 = 0x00;TH0 = 0xDC;
~怎么知道爆表的
通过手册找一找,发现在TCON寄存器当中,TCON寄存器的bit5(TF0)能表示爆表
TF0:定时器/计数器T0溢出(爆表)中断标志,从初始值开始加1计数,当最高位产生溢出时,由硬件置 “1” TF0,向CPU请求中断,一直保持CPU响应该中断时,才由硬件清“0”,TF0() ,才由硬件清“0”TF0(TF0也可有程序查询清“0”).
当爆表的时候,硬件会修改bit5上的数据,改成1
TR0 = 1时允许开始计数,当TR0 = 0时禁止开始计数
~定时器使用是有很多种模式的
定时器模式寄存器:TMOD来选择定时器模式,(7.1.2章节)低四位管理定时器0,高四位管理定时器1.
TMOD的M0和M1相互配合来确定定时器里面的模式,选择工作方式1,TMOD的bit0,bit1配置成 0 1,选择16位的定时器功能
定时器控制LED灯的闪烁
#include "reg52.h"
sbit led = P3^6;
void main()
{
int cnt = 0;
led = 1;
//1.配置定位器0工作模式位16位
TMOD = 0x01;//TMOD的bit0和bit1 配置成16位 0 1方式
//2.给初值,定一个10ms
TL0 = 0x00;
TH0 = 0xDC;
//3.开始计时
TR0 = 1;//根据芯片手册,TR0 = 1的时候开始计时
TF0 = 0;//其初始值本身就为0.
//4. 爆表了,操作led,累计到1s,在操作led
// 爆表了,变量加1,加100次就是1s,每隔1s转换led状态
while(1){
if(TF0 == 1){//当爆表的时候,硬件会修改bit5(TF0)上的值位1,如果不用中断,我们用代码清零
//这里不用中断,所以用软件清0
TF0 = 0;
cnt++;
//重新给初值
TL0 = 0x00;
TH0 = 0xDC;
//每爆表一次,就赋初值,一共赋100次之后为1s
if(cnt == 100){
cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一个1s
led = !led;//每经过一秒,翻转led的状态
}
}
}
//爆表了,变量加1,加100次就是1s,每隔1s转换led状态
}
三组
四个二进制数表示一位16进制数
8421法则进制的转换(方便人类来看,对计算机底层来说,不关心进制010101)
配寄存器推荐用按位操作,清零的时候,对应的需要清零的位&0,不需要清0的位&1
(1与上任何数都不变,0与上任何数都变成了0)
1或任何数都保持原来的不变
中断系统
中断系统是使CPU具有对外界紧急事件实时处理能力而设置的
函数是由软件调用,而中断服务程序是由硬件调用
使用C语言编程,中断查询词序号,就是中断编号
中断处理函数,中断处理向量
注册函数,并且给函数后多一个interrupt
interrupt 0 1 2 3 4 5 6 7;在转换成0101格式的时候,他会被放入单片机的一个特殊位置
定时器中断相关寄存器
EA串口相关,T0的的溢出中断允许位
中断寄存器
CPU能响应定时器0中断的条件:需要配置IE寄存器的bit1:ET0 bit7:EA
1.ET0中断允许要置1 ET0 = 1
2.EA总中断要置1 EA = 1
PWM(波形)开发SG90
脉冲宽度调制
占空比: 一个波形周期内,高电平占据时长的百分比
如何实现PWM信号输出
通过芯片内部模块输出,一般观察手册或者芯片口IO都会表明这个是否是PWM口
控制舵机
1.什么是舵机
最便宜的舵机sg90,常用三根或者四根接线,黄色位PWM信号控制,
用处:垃圾桶项目开盖用,智能小车的全比例转向,摄像头云台,机械臂等
常见的有0-90°,180°,360°
黄:PWM信号
红:VCC
灰:GND
2.怎么控制舵机
向黄色信号线“灌入”PWM信号
、PWM波的频率不能太高,大约50hz,即周期0.02s(周期等于频率的倒数,
即1/50hz=0.02s=20ms),20ms左右
数据:
0.5ms---------0度 2.5%对应函数中占空比为250
1.0ms---------45度 5.0% 对应函数中占空比为500
1.5ms---------90度 7.5% 对应函数中占空比为750
2.0ms---------135度 10% 对应函数中占空比为1000
2.5ms---------180度 12.5% 对应函数中占空比为1250
定时器中断方式控制LED
#include "reg52.h"
sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向p3组IO口的第6口
//用来计数
int cnt = 0;
void Delay300us() //@11.0592MHz
{
unsigned char i;
i = 135;
while (--i);
}
void Time0Init()
{
//1.配置定时器0工作模式为16位
TMOD = 0x01;
//2.给初值,定一个10ms出来
TL0 = 0x00;
TH0 = 0xDC;
//3.打开定时器0中断
ET0 = 1;
//4.打开总中断
EA = 1;
//5.开始计时
TR0 = 1;
TF0 = 0;
}
void main()
{
led1 = 0;//根据电路图,低电平点亮led
Time0Init();
while(1){
led2 = 0;
Delay300us();
led2 = 1;
Delay300us();
}
}
void Time0Handler() interrupt 1
{
cnt++;//统计爆表次数
//重新给初值
TL0 = 0x00;
TH0 = 0xDC;
if(cnt == 100)
{
cnt = 0;
led1 = !led1;
}
}
舵机编程实战
#include "reg52.h"
sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向p3组IO口的第6口
sbit sg90_con = P1^1;//舵机想要控制它,碧=必须街道单片机的某个引脚
//用来计数
int cnt = 0;
int jd;//角度
void Time0Init()
{
//1.设置定时器0的工作模式为16位
TMOD = 0x01;
//2.设置0.5ms延时
TL0 = 0x33;
TH0 = 0xFE;
//3.打开定时器0中断
ET0 = 1;
//4.打开总中断
EA = 1;
//5.开始计时
TR0 = 1;
TF0 = 0;
}
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
Delay2000ms();//首先启用软件延迟,让系统稳定
Time0Init();//定时器初始化
jd = 1;//角度等于1,初始化角度是0度,0.5ms的高电平
//刚开始的角度设定为1
cnt = 0;
//为了让程序的误差减小
sg90_con = 1;
while(1){
//只要角度变了,就让 cnt = 0;防止角度变的时候cnt 还在中间,产生误差
//让角度跳变,每隔两秒变一次,4与1切换
jd = 4;// 135度,2ms高电平
cnt = 0;//希望同步,所以把cnt设置成0
Delay2000ms();//延迟2s ,减小误差
jd = 1;// 0度,0.5ms高电平
cnt = 0;
Delay2000ms();
}
}
void Time0Handler() interrupt 1
{
//次数增加
cnt++;
sg90_con = 1;//刚进来就让他维持高电平
//重新赋初值
TL0 = 0x33;
TH0 = 0xFE;
//由main函数来控制jd
//jd等于1和4是不一样的反馈,所以需要让cnt<jd
//波形的控制(PWM波)
if(cnt<jd){ //判断,在第一次高电平,之后都维持低电平
sg90_con = 1;//维持高电平
}else{
sg90_con = 0;//维持低电平,一直维持到40
}
//判断,等于40 一个周期结束,cnt重置,sg90恢复高电平
if(cnt == 40)
{
cnt = 0;
sg90_con = 1;
}
}