2013-08-04 17:32:52 czjsky818 阅读数 11871
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3411 人正在学习 去看看 朱有鹏

STC51单片机一般是通过串口线下载程序到MCU。但是,有时候单片机放在作品上,串口线不够长,不方便下载,或者频繁拔插单片机,也不方便。

本方法,通过笔记本蓝牙,蓝牙串口模块HC-05,即可实现STC51单片机无线下载程序到MCU。


需要以下准备:

  1. 有蓝牙模块的笔记本。

  2. 蓝牙串口模块HC-05

  3. STC51单片机

  4. STC-ISP V6.53(只要能任意选择COM口的都行。)

  5. USB转串口模块


第一步:

 打开笔记本蓝牙模块。首先你要确定你有蓝牙模块和装好相应的驱动,这里我就不详细展开了。不同笔记本打开方式不同。我的联想Y笔记本如图1:


第二步:

将USB转串口和HC-05的VCC,GND,相连,TXD接RXD,RXD接TXD。将USB转串口模块插入笔记本。此时HC-05指示灯应该是快速闪烁。

如上图,点击添加设备,搜索到HC-05后连接,输入设备的配对码 1234 ,如图2,


然后就连接成功,在 控制面板\硬件和声音\设备和打印机 里便可以看到HC-05了。在HC-05上右键,属性,硬件,便可以看到COM口号,COM28,如图3。



第三步:

将HC-05模块的PIO11置高(我买的模块有个按键),上电,模块便进入AT命令响应模式。此时HC-05指示灯应该是慢速地闪烁。

此时可以打开任意串口助手软件,如STC-ISP的串口助手,设置波特率38400,数据位8位,停止位1位,无校验位,无流控制。

串口发送字符: AT(后面要加个回车键,我之前不知道,以为没进入AT模式),成功则返回OK。

接下来设置HC-05工作模式:波特率9600,数据位8位,停止位1位,偶校验,无流控制。串口发送字符:AT+UART=9600,0,2

然后就可以关闭串口了。



第四步:

将HC-05插到单片机上,还是一样,VCC,GND,相连,TXD接RXD,RXD接TXD。

硬件部分就完成了。


第五步:

在单片机程序中加入ISP.c,ISP.h,在程序开关调用函数 UARTInit(); 实现STC51单片机的ISP。

/******************************************************************************
* 文    件: ISP.c
* 原作者: 李锋源
* 修  改: ZhnJa 
* 创建日期: 2011-7-15
* 修改日期: 2013-8-01
* 说 明: 原文件为阿土开发板的Driver.c,提取出来的ISP下载程序。
******************************************************************************/

#include "ISP.h"
#include "STC12C5A60S2.h"
#include <intrins.h> 

#ifdef	Self_Define_ISP_Download			//如果有自定义ISP下载功能
unsigned char bufptr;
code unsigned char passward[]={ICPCODE};
unsigned char buf[sizeof(passward)*2];		//静态串口缓冲区
#endif
 
/******************************************************************************
*                               UART初始化            
*描    述:串口初始化函数, 通常是在使用串口前调用本函数来进行初始化, 通常是在
*          main函数中调用。
*入口参数:无
*返    回:无
*注    意:串口使用的是中断模式
******************************************************************************/
void UARTInit(void)
{
	#define Fclk 11059200UL	//晶振 11.059M 不可以写成11059200
	#define BitRate 9600UL	//9600b/s
	unsigned char i;
	unsigned int j;
#ifdef	Self_Define_ISP_Download   //自定义下载使用到
	bufptr = 0;
	for( i=0; i<sizeof(buf); i++)
	{
		buf[i] = 0;
	}
#endif
	EA=0; 							//暂时关闭中断
	TMOD &= 0x0F;
	TMOD |=0x20;    				//定时器1工作在模式2,自动重装模式
	SCON=0x50;     					//串口工作在模式1
	TH1=256-(Fclk/(BitRate*12*16)); //计算定时器重装值
	TL1=256-(Fclk/(BitRate*12*16));
	PCON|=0x80;    					//串口波特率加倍
   // ES=1;         				//串行中断允许
	TR1=1;        					//启动定时器1
	REN=1;        					//允许接收 
	EA=1;         					//允许中断 

  	for(i=0;i<8;i++)			 	//短暂延时判断有无ISP下载命令
	{	
	 	for(j=0;j<40000;j++)
		{
		 	if(RI)
			{
				RI = 0;
				IAP_CONTR = 0x60;	 //复位到IAP
			}
		}
	}
	ES=1;         					//串行中断允许
}


/******************************************************************************
*                               延时1s函数            
*描    述:延时1s函数,在UartInit()调用供ISP延时。
*入口参数:无
*返    回:无
*注    意:
******************************************************************************/
void delay1s(void)
{
 	unsigned char i,j,k;
	for(i=0;i<200;i++)
	{
	 	for(j=0;j<200;j++)
		{
			k = 10;
			while(k--);
		}
	}
}
/******************************************************************************
*                           发送一个字符            
*描    述:向串口发送一个字符。
*入口参数:要发送的字符
*返    回:无
*注    意:
******************************************************************************/
void SendByte(unsigned char c)	 
{
    SBUF = c;
    while(!TI);
    TI = 0;
}
/******************************************************************************
*                          发送一个字符串            
*描    述:向串口发送一个字符串
*入口参数:*s要发送的字符串
*返    回:无
*注    意:
******************************************************************************/
void SendStr(char *s)			
{
	while(*s)
	{
		SendByte(*s++);
	}
}

/******************************************************************************
*                               串口0中断            
*描    述:串口0(UART0)中断。
*入口参数:无
*返    回:无
*注    意:
******************************************************************************/
void UartISR(void) interrupt 4
{
#ifdef Self_Define_ISP_Download
	
	unsigned char ptScr,ptDst;
	if(RI)
	{
		RI = 0;				//清标志位
		buf[bufptr] = SBUF;
		ptScr = bufptr;	
		if(bufptr==sizeof(buf))
		{
			bufptr = 0;
		}
		else
		{
			bufptr++;
		}
		while(buf[ptScr] == passward[ptDst])
		{
			if(ptScr == 0)
			{
				ptScr = sizeof(buf)-1;
			}
			else
			{
				ptScr--;
			}
			if(ptDst == 0)
			{
			//	reset();
			delay1s();            
			//复位前提示程序
			IAP_CONTR = 0x60;	 	//复位到IAP
			}
			else
			{
				ptDst--;
			}	
		}
		//用户程序开始
		
		
		//用户程序结束
	}//End if(RI) 
	if(TI)							//发送完成
	{		   	
	 	TI = 0;						//清标志位
	}
#else		   						//如果不使用自定义ISP下载程序
	if(RI)
	{
		RI = 0;
	}
	else
	{
	 	TI = 0;
	}
#endif
}

/*======================End Of File====================*/

/******************************************************************************
* 文    件: ISP.h
* 原作者: 李锋源
* 修  改: ZhnJa 
* 创建日期: 2011-7-15
* 修改日期: 2013-8-01
******************************************************************************/
#ifndef	__ISP_H__
#define __ISP_H__

#include "STC12C5A60S2.h"
//系统配置
#define Self_Define_ISP_Download			//ISP下载
#define ICPCODE		0x12,0x34,0x56,0x78,0x90,0xAB,0xCD,0xEF
#define FOSC	11059000UL
#define T100HZ  (FOSC/12/100)


//函数声明

//串口
void UARTInit(void);
void UARTInit(void);

void SendByte(unsigned char c);
void SendStr(char *s);

void delay1s(void);


#endif

第六步:

先用普通的正常下载方式将包含有ISP功能的程序下载到STC51单片机上。

打开STC-ISP(V6.53),设置如图,点击发送自定义下载命令即可实现远程下载。

补充:最高,最低波特率要设置为9600



说明1:
ISP,即In-System Programming,在线编程。
具有ISP功能的单片机芯片,可以通过简单的下载线直接在电路板上给芯片写入或者擦除程序,并且支持在线调试。
说明2:
须先下载一次有ISP功能的程序到单片机,之后才能实现冷启动下载程序,即ISP功能。

2018-05-19 22:37:03 Prediction_185 阅读数 2379
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3411 人正在学习 去看看 朱有鹏

蓝牙舵机篇  

引语  本系列博客将分为三篇来讲解,第一篇讲解如何通过HC-05蓝牙模块控制舵机,第二篇会介绍HC-SR04超声波模块的测距程序,第三篇会将两者组装在一起。


最终目的:通过手机连接蓝牙向单片机发送信号,单片机收到信号后向舵机发送pwm信号,让舵机达到相应的角度。

实现效果需要达到的目标:

1.会使用HC-05蓝牙模块,了解51单片机的串口通信。

2.会用51单片机输出pwm波控制舵机,并校正舵机的误差。

材料:51单片机最小系统、HC-05蓝牙模块、舵机、杜邦线、数据传输线。

51单片机最小系统:如图:


HC-05


如上图所示为蓝牙模块与51单片机的连接方式

那么如何让手机控制单片机呢?

这里我们需要下载一个app,如图


我们可以在聊天栏中,向单片机发送信息,手机将信息分解为ASCII码发给单片机。单片机接受到的也是ASCII码,因此在下面的程序中的case语句中是以16进制来分情况的。

舵机:我们这里所使用的是SG-90舵机 如图


将舵机的橙线连接到P1.2接口

              红线连接到VCC口

              棕色连接到GND

想要控制舵机,那么我们就需要一个周期T = 20ms,高电平的时间(t)等于0.5ms-2.5ms之间的这样一个信号。 
以下是高电平持续的时间(t)与舵机的关系。


t = 0.5ms——————-舵机会转动 0 ° 
t = 1.0ms——————-舵机会转动 45° 
t = 1.5ms——————-舵机会转动 90° 
t = 2.0ms——————-舵机会转动 135° 

t = 2.5ms——————-舵机会转动180° 

但是在实际的应用中,我发现每一个舵机都存在误差,也就是说输出对应空占比的pwm信号,舵机不会精确地转动到相应的度数。因此我将在下面的程序中加以校正。

以下是代码

#include <AT89x51.H>//注意这里的头文件为 <AT89x51.H>

#define SEH_PWM P1_2//舵机PWM口定义

unsigned char SEH_count=5;
unsigned char count=0;


unsigned char T0RH = 0xff;  //T0重载值的高字节
unsigned char T0RL = 0xa3;  //T0重载值的低字节
unsigned char RxdByte = 0;  //串口接收到的字节

void ConfigTimer0();
void ConfigUART(unsigned int baud);

void PWM(unsigned char x)
{
	SEH_count=x;
}

void main()
{
    EA = 1;       //使能总中断
;
    ConfigTimer0();   //配置T0定时1ms
    ConfigUART(9600);  //配置波特率为9600
    
    while (1)
    {  
					switch(RxdByte)
				{
					case 0x31:{
											PWM(5);//手机向单片机发送‘0’,舵机转到0度    
										};break;
					case 0x32:{
										PWM(10);//手机向单片机发送‘1’,舵机转到45度  
										};break;
					case 0x33:{
										PWM(15);//手机向单片机发送‘2’,舵机转到90度  
										};break;
					case 0x34:{
										PWM(20);//手机向单片机发送‘3’,舵机转到135度  
										};break;
					case 0x35:{
										PWM(25);//手机向单片机发送‘4’,舵机转到180度  
										};break;
					case 0x36:{
										;//														
										};break;
					case 0x37:{
									   ;//																
										};break;
					case 0x38:;break;
				}
    }
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0()
{
  


    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    SCON  = 0x50;  //配置串口为模式1
    TMOD &= 0x0F;  //清零T1的控制位
    TMOD |= 0x20;  //配置T1为模式2
    TH1 = 256 - (11059200/12/32)/baud;  //计算T1重载值
    TL1 = TH1;     //初值等于重载值
    ET1 = 0;       //禁止T1中断
    ES  = 1;       //使能串口中断
    TR1 = 1;       //启动T1
}

/* T0中断服务函数,完成LED扫描 */
void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
	  if(count <= SEH_count) 
    {
     
        SEH_PWM = 1;
    }
    else
    {
        SEH_PWM = 0;
    }

    
    count++;
    if (count >= 200) 
    {
        count = 0;
			
    }
	
}
/* UART中断服务函数 */
void InterruptUART() interrupt 4
{
    if (RI)  //接收到字节
    {
        RI = 0;  //手动清零接收中断标志位
        RxdByte = SBUF;  //接收到的数据保存到接收字节变量中
        SBUF = RxdByte;  //接收到的数据又直接发回,叫作-"echo",
                         //用以提示用户输入的信息是否已正确接收
    }
    if (TI)  //字节发送完毕
    {
        TI = 0;  //手动清零发送中断标志位
    }
}

2019-12-17 11:20:17 I_am_hardy 阅读数 23
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3411 人正在学习 去看看 朱有鹏

硬件驱动

  • 初始化
    拿到蓝牙模块先将其串口与电脑连接,波特率一般默认为9600,由于我用的是12M的晶阵,产生9600的波特率精度不行所以用4800的波特率。通过电脑串口调式助手发送AT指令修改蓝牙模块的波特率为4800,这些指令在资料里应该都有。(指令之后还有个回车)
AT+BAUD3

  • 然后接贴下面代码烧到单片机上去观察相应输出IO的电平看是否正确完事,再按照备注上的说明搭建小车就完美执行(电机驱动用的L289N)
#include "reg52.h"			 
#include<intrins.h>

//控制四轮的小车IO
#define control P0

typedef unsigned int u16;
typedef unsigned char u8;

//车灯控制,为0时亮
sbit LED = P2^4;

//电机驱动使能控制IO
//前面(俯视)
//motor1   motor2
//motor3   motor4

//control  11 11 11 11
//         m1 m2 m3 m4
//所有的都是01向前,10向后
sbit motor1=P2^0;
sbit motor2=P2^1;
sbit motor3=P2^2;
sbit motor4=P2^3;



//保存串口接收到的数据
u8 recv[50];
u8 count=0,length=0;

//速度调节
u16 time=0;
u16 speed=50;

//小车状态
u8 state=4;

//延迟10us
void delay(u16 i)	
{
	while(i--);	
}




//初始化
void init()
{
	//发送AT指令初始化蓝牙模块和客户端对应,客户端的UUID就是这个,还有蓝牙的名称为hardy
	char *a="at+namehardy\r\n";
   char *b="at+UUID0xFFE0\r\n";
	char *c="at+char0xFFE1\r\n";
	TMOD = 0x21;	  //T1工作方式2,T0工作方式2
	//设置波特率为4800
	SCON = 0x50;
	PCON = 0X80;	//波特率加倍
	TL1 = 0XF3;
	TH1 = 0XF3;	
	TR1 = 1;   //打开定时器

	//T0定时器初始化  100us
	TH0 = 0x0FF;
    TL0 = 0x0A4;
    ET0 = 1;
    TR0 = 1;
	
	IT0=1;	//设置外部中断0的触发方式为下降沿
	EX0=1;	//开启外部中断0

	EA = 1;	 //允许总中断
	ES = 0;  
	delay(50000);  //适当延迟给模块反应时间
    while(*a!='\0')
    {
        SBUF=*a;   
        while(!TI);  
        TI=0;        
        a++;
    }
	delay(50000);
    while(*b!='\0')
    {
		SBUF=*b;  
        while(!TI);  
        TI=0;
        b++;
    }
	delay(50000);
    while(*c!='\0')
    {
		SBUF=*c;  
        while(!TI);
        TI=0;
        c++;
    }
	ES = 1;
}


//输出PWM控制车速
void PWM(){
	if(time>100)  //PWM周期为100*100us
		{
			time=0;
		}
	if(time <speed)	  
		{
			motor1=1;
			motor2=1;
			motor3=1;
			motor4=1;
		}
	else
		{
			motor1=0;
			motor2=0;
			motor3=0;
			motor4=0;
	 	}

}


//通过串口发送字符串,发送到手机客户端用于提示
void send(char *str)  
{                
    ES=0;  //发送时先将串口接收中断关掉发送完成再打开
     while(*str!='\0') 
    {                      
        SBUF=*str;
        while(!TI);
        TI=0;    
        str++;
    }
    ES=1; 
}

//获取速度用以传入客户端显示
char* getspeed(){
	if(speed<20){
		return (char*)"speed:1";
	}
	if(speed>=20&&speed<40){
		return (char*)"speed:2";
	}
	if(speed>=40&&speed<60){
		return (char*)"speed:3";
	}
	if(speed>=60&&speed<80){
		return (char*)"speed:4";
	}
	if(speed>=80){
		return (char*)"speed:5";
	}
	return "error";
}

//获取小车状态用以传入客户端显示
char* getstate(){
	if(state==0){
		return (char*)"go";
	}
	if(state==1){
		return (char*)"back";
	}
	if(state==2){
		return (char*)"trun left";
	}
	if(state==3){
		return (char*)"trun right";
	}
	if(state==4){
		return (char*)"stop";
	}
	if(state==5){
		return (char*)"speed:5";
	}
	if(state==6){
		return (char*)"speed:5";
	}
	return "error";
}


//前进
void forword(){
	motor1=1;
	motor2=1;
	motor3=1;
	motor4=1;
	//对应01010101
	control=0x55;
	state = 0;
	send(getstate());
}
//后退
void back(){
	motor1=1;
	motor2=1;
	motor3=1;
	motor4=1;
	//对应10101010
	control=0xAA;
	state = 1;
	send(getstate());
}
//左转
void trunLeft(){
	//只有电机2前进,其他停止
	motor1=0;
	motor2=1;
	motor3=0;
	motor4=1;
	//对应xx01xxxx
	control=0x55;
	state = 2;
	send(getstate());
}
//右转
void trunRight(){
	//只有电机1前进,其他停止
	motor1=1;
	motor2=0;
	motor3=3;
	motor4=0;
	//对应01xxxxxx
	control=0x55;
	state = 3;
	send(getstate());
}
//停止
void stop(){
	 //全部电机使能停止
	motor1=0;
	motor2=0;
	motor3=0;
	motor4=0;
	state = 4;
	LED=1;
	send(getstate());
}
//开灯
void trunOnLight(){
	char *error = "light on";
	send(error);
	LED = 0;
	_nop_(); 
	_nop_(); 
	_nop_();
	LED = 1; 
}
//加速
void acce(){
	if(speed<100){
		speed = speed+10;
	}
	send(getspeed());
}
//减速
void slow(){
	if(speed>0){
		speed = speed-10;
	}
	send(getspeed());
}
//其他
void other(){
	char *error = "error";
	send(error);
}

void main()
{	
	init();
	 //初始化全部电机使能停止
	motor1=0;
	motor2=0;
	motor3=0;
	motor4=0;
	control=0xff;
	LED = 1;
	P1=0xFF;
	while(1)
	{
		//客户端发出指令
		if(length != 0){
			switch(recv[0]){
				//前进指令
				case 'f': forword();break;
				//后退指令
				case 'b': back();break;
				//左转指令
				case 'l': trunLeft();break;
				//右转指令
				case 'r': trunRight();break;
				//停止指令
				case 's': stop();break;
				//开灯指令
				case 'o':trunOnLight();break;
				//加速指令
				case 'c':acce();break;
				//减速指令
				case 'w':slow();break;
				//未知指令
				default:other(); break;
			}
			length=0;
		}
		//如果前进或者后退则speed速度有效,转弯全速
		if(state==0||state==1){
			PWM();
		}
	}		
}


//外部中断0触发时,读取P0中的控制数据
//这个用于另外单片机互动的,由于这个单片机只有两个定时器用完了,超声波模块需要用没有了
void ex0() interrupt 0 
{
	//外部信号拉低,对电机进行控制
	if(P1 != 0xFF){
		if(P1 == 0xFE){
			forword();
		}
		if(P1 == 0xFD){
			back();
		}
		if(P1 == 0xFB){
			trunLeft();
		}
		if(P1 == 0xF7){
			trunRight();
		}
		if(P1 == 0xEF){
			stop();
		}
		P1 = 0xFF;	
	}
}

//计数做PWM的产生
void Time0(void) interrupt 1   
{
	TH0 = 0x0FF;
    TL0 = 0x0A4;
	time++; 
}

//串口接收中断接收蓝牙模块发来的数据
void rev() interrupt 4
{
	//接收数据并且手动清空标志位
	char res;
	res=SBUF;
	RI = 0;
	//将字符串在符号$和符号#之间的保存到数组中 ,并记录长度,用$#两个符号包围数据防止干扰这里接收到的是数据的ASCII,比如客户端发送$过来接收到的ASCII码是35
	if(res == 35){
		length=count;
		count = 0;
	}
	else{
		if(res == 36){
			length=0;
			count = 0;
		}
		else{
			recv[count]=res;
			count++;
		}
	}
}

手机客户端——微信小程序

  • 客户端需要很麻烦的蓝牙连接过程,已经全部写好了直接调用接收和发送函数就可以了。代码上千行就不帖了,GitHub地址https://github.com/hddhardy/xiaoche
2019-04-01 17:18:05 qq_41865502 阅读数 934
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3411 人正在学习 去看看 朱有鹏

在这里插入图片描述

蓝牙模块:HC05
波特率:9600
校验位:无
停止位:1

HC05与电脑的蓝牙配对后生成传入传出两个COM口,使用传出COM口

蓝牙与单片机接线:
5V–5V
GND–GND
TX–3.0
RX–3.1

第一次需要用常规方式将下方代码写入

main.c
#include <reg52.h>
#include “stc_isp_download.h”

sbit LED = P0^0;

void main()
{
Init_Iap_Download();
LED = 1;
while (1)
{
LED = 0;
}
}

stc_isp_download.c
#include “stc_isp_download.h”

void Init_Iap_Download()
{
TMOD=0X20;
SM0=0;
SM1=1;
REN=1;
TH1=0XFD;
TL1=0XFD; //波特率 9600
TR1=1; //校验位 无
EA=1; //停止位 1
ES=1;
}
void Rceive()interrupt 4
{
unsigned char i=0;
unsigned int j,k;

if(TI==1)
{
	TI=0;
}
else
{
	RI=0;
	i=SBUF;
	if(i==Download_command)
	{
		for(j=1000;j>0;j--)
		for(k=123;k>0;k--);
		Iap_Download =0x60;
	}
}

}

stc_isp_download.h
#ifndef stc_isp_download
#define stc_isp_download

#include <reg52.h>
#define Download_command 0xf1 //功能码
sfr Iap_Download=0xE7;//软复位地址
void Init_Iap_Download();

#endif

2018-05-07 18:17:02 qq_41570228 阅读数 11879
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3411 人正在学习 去看看 朱有鹏

  51单片机是市面上比较普及的单片机种类,同时也深受广大电子爱好者的青睐。在51单片机的众多功能中串口通信占据了重要的地位,通过串口通信,我们可以实现51单片机与其他设备的互联,增加了学习的趣味性。

  HC-05蓝牙模块为主从一体的蓝牙模块,并可与手机实现实时的通信。将单片机的串口通信通过HC-05进行扩展从而实现无线通信,更可使用手机来控制单片机完成工作。

 要完成单片机与Android手机的无线通信,首先我们要在写好单片机的控制程序,因为HC-05只是对串口通信功能进行延伸, 并不能独立完成通信。

 编写串口通信的程序中首先我们要对串口的配置进行初始化

void UartConfigurationInit()
{
    TMOD=0x20;  //设置定时器1工作方式为方式2   
    TH1=0xfd;  	  //波特率9600
    TL1=0xfd;  
    TR1=1;      //启动定时器1     
    SM0=0;SM1=1;      //串口方式1         
    REN=1;      //允许接收   
    PCON=0x00;  //关倍频   
    ES=1;       //开串口中断   
    EA=1;       //开总中断
}

配置好串口后,在编写发送函数前我们需要对串口发送数据的原理有个了解:

转码过程:

发送十进制数:查询ASCII码表后发送相应的字符 ,如SBUF=65;则会收到字符‘A’;

发送字符:原样输出

发送字符串:强行对SBUF传递字符串会造成输出乱码,得不到想要的结果。想要发送字符串则需要运用指针,每次发送时发送指针指向的那个字符,因为发送频率很快,最后输出时组合起来还是一条字符串。

实现整数转为字符串发送:

   0x30对应的字符‘0’,当我们要发送一个整数时,需要将该整数按最高位到最低位得到顺序依次发送,发送时需要在原始数据上加上0x30或者48,则会输出相应的数字字符。


字符发送函数:

void PostChar(uchar character)  
{     
	    SBUF=character;   //发送单个字符
	    while(!TI);TI=0; //发送完成标志 
}

字符串的发送需要依靠字符发送函数来实现:

  这里加了一个延时函数delay(),因为在实际与手机通信中我发现发送速度过快会产生严重的数据丢失,因此加上一个延时可以较好的保证数据的准确度,具体延时数据根据大家实际需要调整。

void  PostString(uchar *p)  
{  
	    while(*p)  	   //若指针指向的地址为空,则跳出循环
	    {  
	        PostChar(*p); //指针第一次默认指向首地址
			delay(20);  //延时,作用为提高发送准确度
	        p++;  
	    }	  
}

十进制数据发送:

 因为十进制数据不能直接发送,所以要先加上0x30或者48后再转为字符型。

void IntConversionChar(uint number)
{
       uint model;	//模
       uint numberByte; //十进制数据不同位上的值

     for(model=1000;model>=1;model=model/10) //model的取值根据实际需要选择,选择过大会浪费资源

      {
            numberByte = number/model;	//相除取整
			//当取到整数数据的最高位时,将其加上0x30或者48并转为字符型后发送
            if(numberByte >=1 ) PostChar((uchar)(numberByte%10+0x30));
      		//if(numberByte >=1 ) PostChar((unsigned char)(numberByte%10+48));
	  }	
}

以上就是51单片机使用HC-05蓝牙模块与Android手机通信的程序的要点和原理。

完整程序:

https://download.csdn.net/download/qq_41570228/10398277



没有更多推荐了,返回首页