单片机学习

刚开始代码单纯的使用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;
	  }


}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值