51单片机嵌入式开发
STC89C52的嵌入式 遥控器 控制步进电机 转速 和 转向 操作并 printf打印信息
- 51单片机嵌入式开发
- STC89C52的嵌入式 遥控器 控制步进电机 转速 和 转向 操作并 printf打印信息
- 1 概述
- 2 硬件电路
- 2.1 遥控器
- 2.2 红外接收器电路
- 2.3 STC89C52单片机电路
- 2.4 数码管显示电路
- 2.5 串口打印电路
- 2.6 步进电机电路
- 3 工程代码实现
- 3.1 红外接收程序
- 3.2 定时器程序
- 3.3 数码管显示程序
- 3.4 外部中断程序
- 3.5 串口打印程序
- 3.6 步进电机程序
- 3.7 演示效果
- 4 设计总结
STC89C52的嵌入式 遥控器 控制步进电机 转速 和 转向 操作并 printf打印信息
1 概述
基于STC89C52单片机控制步进电机并通过遥控器控制转速和转向,同时使用printf打印信息是一个涉及到多个方面的复杂项目。下面是一个简单的设计思路:
(1) 在C51单片机上,连接HX1838红外解码器、数码管和LED。将HX1838的信号引脚连接到C51单片机的外部中断引脚(例如INT0),数码管的CLK引脚连接到C51单片机的某个IO口引脚,数码管的DIO引脚连接到C51单片机的另一个IO口引脚,LED连接到C51单片机的某个IO口引脚。
(2) 在C51程序中,定义并初始化所需的IO口和外部中断。
(3) 编写中断服务函数以处理红外解码。当外部中断触发时,读取HX1838接收到的红外信号并解码。
(4) 根据解码结果,使用适当的算法将其转换为数码管的显示数据。
(5) 将数码管的显示数据发送到数码管的CLK和DIO引脚,以控制数码管显示解码结果。
(6) 根据解码结果的状态,设置LED引脚状态以控制LED的显示。
(7) 通过循环等待的方式持续接收和处理红外信号,并更新数码管和LED的显示。
(8) 通过循环等待的方式,持续接收和处理红外信号,并更新数码管和LED的显示。
(9) 根据不同的指令信息控制步进电机的转速和转向。
2 硬件电路
2.1 遥控器
外部遥控器的编码见下图,我们用0x44、0x40、0x07、0x15这四个按键控制步进电机的转速和转向。
2.2 红外接收器电路
红外接收器电路见下图:
2.3 STC89C52单片机电路
单片机接口电路见下图:P10~P13接步进电机。
2.4 数码管显示电路
数码管显示电路接口电路见下图,在数码管0和1进行显示16进制的红外线接收码:
2.5 串口打印电路
串口打印电路接口电路见下图(其实用下载电路也能实现串口的通讯):
2.6 步进电机电路
步进电机电路如下:
将P1端口跳线接到左边位置处,ABCD对应位置,将步进电机的排母接到右边位置,红色引线为VCC。
3 工程代码实现
工程、主程序及includes.h如下:
//main.c文件
#include "includes.h"
///******************************************************************/
///* 微秒延时函数 //10us */
///******************************************************************/
//void delay_us(unsigned int us)//delay us
//{
// while(us--)
// {
// }
//}
///******************************************************************/
///* 微秒延时函数 */
///******************************************************************/
//void delay_ms(unsigned int Ms)//delay us
//{
// while(Ms--)
// {
// delay_us(100);
// }
//}
/*------------------------------------------------
延时子程序
------------------------------------------------*/
void delay(unsigned int cnt)
{
while(--cnt);
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
bit flag = 0;
sys_timer_init();
sys_exit_init();
sys_uart_init();
// sys_ledtube_on2();
//
// sys_ledtube_on1();
delay(10);
//首先定义处于什么状态,
//tx1838_type = 1;
printf("Hello world~~");
byj48_value = 300;
while (1)
{
// sys_tx1838_test();
if(tx1838_flag)
{
tx1838_flag = 0;
hx1838_transform(tx1838_value);
}
sys_28byj48_func(byj48_type,byj48_value);
if(flag)
{
flag = 0;
sys_keynum_ledon(tx1838_value>>4,0);
}
else
{
flag = 1;
sys_keynum_ledon(tx1838_value&0xF,1);
}
}
}
//includes.h文件
#ifndef __INCLUDES_H__
#define __INCLUDES_H__
//#include<reg52.h>
#include<intrins.h> //汇编指令_nop_
#include<stdio.h> //标准输入输出
//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。
//8051 为每个机器周期 12 时钟
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。
//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。
//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"
//应用层头文件
//#include "c51_gpio.h"
#include "c51_ledtube.h"
//#include "c51_key.h"
#include "c51_timer.h"
#include "c51_exit.h"
//#include "c51_lcd1602.h"
//#include "c51_iic.h"
#include "c51_tx1838.h"
#include "c51_uart.h"
#include "c51_28byj48.h"
extern void delay(unsigned int cnt);
//extern void delay_us(unsigned int us);//delay us;
//extern void delay_ms(unsigned int Ms);//delay Ms;
#endif
3.1 红外接收程序
实现红外nec解码和根据码位不同,在printf打印不同的字符串。
//c51_tx1838.c文件
#include "includes.h"
unsigned char tx1838_cnt = 0;
unsigned char tx1838_type = 0;
unsigned char tx1838_flag = 0;
unsigned char tx1838_repeat_flag = 0;
unsigned char tx1838_value = 0;
unsigned char tx1838_data[4] = {0};
unsigned int tx1838_time = 0;
//void sys_tx1838_test(void)
//{
// unsigned int time = 0;
// if(!NEC)
// {
// while(!NEC); //等待低电平结束
// TH0 = 0;
// TL0 = 0;
// delay_us(1);
// if(tx1838_type==4)
// {
// tx1838_type =1;
// }
// else
// {
// while(NEC) //等待数据位计时
// {
// if(TH0>30)
// {
// tx1838_type =1;
// break;
// }
// }
// }
// time =(TH0<<8)+TL0; //取得脉冲宽度
//
// switch(tx1838_type)
// {
// case 1:
// {
// if(time>3000 && time<7000) //接收到数据
// {
// tx1838_type = 2;
//
// tx1838_cnt = 0; //接收位数量清0
// tx1838_data[0] = 0;
// tx1838_data[1] = 0;
// tx1838_data[2] = 0;
// tx1838_data[3] = 0;
// }
// else if(time>2000 && time<3000)//接收到重复码
// {
// tx1838_type = 3;
// }
// else
// {
// tx1838_type = 1;
// }
// break;
// }
// case 2:
// {
// tx1838_cnt ++ ;
// if(time>168 && time<800) //接收到数据位为0的时间长度
// {
// }
// else
// {
// if(time>1100 && time<1800) //接收到数据位为1的时间长度
// {
// if(tx1838_cnt<=8)
// {
// tx1838_data[0] |= (1<<(tx1838_cnt-1));
// }
// else if(tx1838_cnt<=16)
// {
// tx1838_data[1] |= (1<<(tx1838_cnt-9));
// }
// else if(tx1838_cnt<=24)
// {
// tx1838_data[2] |= (1<<(tx1838_cnt-17));
// }
// else if(tx1838_cnt<=32)
// {
// tx1838_data[3] |= (1<<(tx1838_cnt-25));
// }
// else
// {
// tx1838_type = 1;
//
// tx1838_cnt = 0; //接收位数量清0
// tx1838_data[0] = 0;
// tx1838_data[1] = 0;
// tx1838_data[2] = 0;
// tx1838_data[3] = 0;
// }
// }
// else //重新解码 //接收到引导码或者结束码,或者接收到的是重复码,本章节不进行演示
// {
// tx1838_type = 1;
//
// tx1838_cnt = 0; //接收位数量清0
// tx1838_data[0] = 0;
// tx1838_data[1] = 0;
// tx1838_data[2] = 0;
// tx1838_data[3] = 0;
// }
// }
//
// if(tx1838_cnt>=32)
// {
// tx1838_type = 4;
//
// switch(tx1838_data[3])//判断数码值
// {
// case 255:sys_keynum_ledon(0);break;//0 显示相应的按键值
// case 254:sys_keynum_ledon(1);break;//1
// case 253:sys_keynum_ledon(2);break;//2
// case 252:sys_keynum_ledon(3);break;//3
// case 251:sys_keynum_ledon(4);break;//4
// case 250:sys_keynum_ledon(5);break;//5
// case 249:sys_keynum_ledon(6);break;//6
// case 248:sys_keynum_ledon(7);break;//7
// case 247:sys_keynum_ledon(8);break;//8
// case 246:sys_keynum_ledon(9);break;//9 显示相应的按键值
// }
// }
// break;
// }
// case 3: //重复码
// {
// tx1838_type = 1;
// sys_keynum_ledon(11);
// break;
// }
// case 4: //结束码
// {
// tx1838_type = 1;
//
// tx1838_cnt = 0; //接收位数量清0
//
// break;
// }
// case 5:
// {
// break;
// }
// default:
// tx1838_type = 1;
// break;
// }
//
// }
//}
void sys_nec_test(void)
{
if(tx1838_type==0) //状态0,空闲状态
{
timer0_set(0); //定时计数器清0
timer0_run(1); //定时器启动
tx1838_type=1; //置状态为1
}
else if(tx1838_type==1) //状态1,等待Start信号或Repeat信号
{
tx1838_time=timer0_get(); //获取上一次中断到此次中断的时间
timer0_set(0); //定时计数器清0
//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
if(tx1838_time>12442-500 && tx1838_time<12442+500)
{
tx1838_type=2; //置状态为2
}
//如果计时为11.25ms,则接收到了repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
else if(tx1838_time>10368-500 && tx1838_time<10368+500)
{
tx1838_repeat_flag=1; //置收到连发帧标志位为1
timer0_run(0); //定时器停止
tx1838_type=0; //置状态为0
}
else //接收出错
{
tx1838_type=1; //置状态为1
}
}
else if(tx1838_type==2) //状态2,接收数据
{
tx1838_time=timer0_get(); //获取上一次中断到此次中断的时间
timer0_set(0); //定时计数器清0
//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
if(tx1838_time>1032-500 && tx1838_time<1032+500)
{
tx1838_data[tx1838_cnt/8]&=~(0x01<<(tx1838_cnt%8)); //数据对应位清0
tx1838_cnt++; //数据位置指针自增
}
//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
else if(tx1838_time>2074-500 && tx1838_time<2074+500)
{
tx1838_data[tx1838_cnt/8]|=(0x01<<(tx1838_cnt%8)); //数据对应位置1
tx1838_cnt++; //数据位置指针自增
}
else //接收出错
{
tx1838_cnt=0; //数据位置指针清0
tx1838_type=1; //置状态为1
}
if(tx1838_cnt>=32) //如果接收到了32位数据
{
tx1838_cnt=0; //数据位置指针清0
if((tx1838_data[0]==~tx1838_data[1]) && (tx1838_data[2]==~tx1838_data[3])) //数据验证
{
//地址 :tx1838_data[0]
//地址反码 :tx1838_data[1]
//数据 :tx1838_data[2]
//数据反码 :tx1838_data[3]
tx1838_value = tx1838_data[2];
//P1 = tx1838_value;
tx1838_flag=1; //红外遥控获取收到数据帧标志位
}
timer0_run(0); //定时器停止
tx1838_type=0; //置状态为0
}
}
}
void hx1838_transform(unsigned char cmd)
{
/*
#define TX1838_CH0 0x45
#define TX1838_CH1 0x46
#define TX1838_CH2 0x47
#define TX1838_VOL1 0x44
#define TX1838_VOL2 0x40
#define TX1838_VOL3 0x43
#define TX1838_EQ1 0x07
#define TX1838_EQ2 0x15
#define TX1838_EQ3 0x09
#define TX1838_0 0x16
#define TX1838_100 0x19
#define TX1838_200 0x0D
#define TX1838_1 0x0C
#define TX1838_2 0x18
#define TX1838_3 0x5E
#define TX1838_4 0x08
#define TX1838_5 0x1C
#define TX1838_6 0x5A
#define TX1838_7 0x42
#define TX1838_8 0x52
#define TX1838_9 0x4A
*/
switch(cmd)
{
case TX1838_CH0:
//printf("Receice cmd : TX1838 receice is TX1838_CH0 !\r\n");
break;
case TX1838_CH1:
//printf("Receice cmd : TX1838 receice is TX1838_CH1 !\r\n");
break;
case TX1838_CH2:
//printf("Receice cmd : TX1838 receice is TX1838_CH2 !\r\n");
break;
case TX1838_VOL1:
byj48_type = 0;
printf("Receice cmd : TX1838 receice is 正转 !\r\n");
break;
case TX1838_VOL2:
byj48_type = 1;
printf("Receice cmd : TX1838 receice is 反转 !\r\n");
break;
case TX1838_VOL3:
printf("Receice cmd : TX1838 receice is 加速 !\r\n");
break;
case TX1838_EQ1:
if(byj48_value<300)
{
byj48_value = 300;
}
byj48_value -= 10;
printf("Receice cmd : TX1838 receice is 加速 !\r\n");
break;
case TX1838_EQ2:
if(byj48_value>1000)
{
byj48_value = 1000;
}
byj48_value += 10;
printf("Receice cmd : TX1838 receice is 减速 !\r\n");
break;
// case TX1838_EQ3:
// printf("Receice cmd : TX1838 receice is TX1838_EQ3 !\r\n");
// break;
// case TX1838_0:
// printf("Receice cmd : TX1838 receice is TX1838_0 !\r\n");
// break;
// case TX1838_100:
// printf("Receice cmd : TX1838 receice is TX1838_100 !\r\n");
// break;
// case TX1838_200:
// printf("Receice cmd : TX1838 receice is TX1838_200 !\r\n");
// break;
// case TX1838_1:
// printf("Receice cmd : TX1838 receice is TX1838_1 !\r\n");
// break;
// case TX1838_2:
// printf("Receice cmd : TX1838 receice is TX1838_2 !\r\n");
// break;
// case TX1838_3:
// printf("Receice cmd : TX1838 receice is TX1838_3 !\r\n");
// break;
// case TX1838_4:
// printf("Receice cmd : TX1838 receice is TX1838_4 !\r\n");
// break;
// case TX1838_5:
// printf("Receice cmd : TX1838 receice is TX1838_5 !\r\n");
// break;
// case TX1838_6:
// printf("Receice cmd : TX1838 receice is TX1838_6 !\r\n");
// break;
// case TX1838_7:
// printf("Receice cmd : TX1838 receice is TX1838_7 !\r\n");
// break;
// case TX1838_8:
// printf("Receice cmd : TX1838 receice is TX1838_8 !\r\n");
// break;
// case TX1838_9:
// printf("Receice cmd : TX1838 receice is TX1838_9 !\r\n");
// break;
default:
printf("Receice cmd : TX1838 receice err!\r\n");
break;
}
}
//c51_tx1838.h文件
#ifndef __C51_TX1838_H__
#define __C51_TX1838_H__
#define NEC P32 //红外线接收头
#define TX1838_CH0 0x45
#define TX1838_CH1 0x46
#define TX1838_CH2 0x47
#define TX1838_VOL1 0x44
#define TX1838_VOL2 0x40
#define TX1838_VOL3 0x43
#define TX1838_EQ1 0x07
#define TX1838_EQ2 0x15
#define TX1838_EQ3 0x09
#define TX1838_0 0x16
#define TX1838_100 0x19
#define TX1838_200 0x0D
#define TX1838_1 0x0C
#define TX1838_2 0x18
#define TX1838_3 0x5E
#define TX1838_4 0x08
#define TX1838_5 0x1C
#define TX1838_6 0x5A
#define TX1838_7 0x42
#define TX1838_8 0x52
#define TX1838_9 0x4A
extern unsigned char tx1838_cnt;
extern unsigned char tx1838_type;
extern unsigned char tx1838_flag;
extern unsigned char tx1838_repeat_flag;
extern unsigned char tx1838_value;
extern unsigned char tx1838_data[4];
extern unsigned int tx1838_time;
//extern void sys_tx1838_test(void);
extern void sys_nec_test(void);
extern void hx1838_transform(unsigned char cmd);
#endif
3.2 定时器程序
//c51_timer.c文件
#include "includes.h"
void sys_timer_init(void)
{
sys_timer0_init();
sys_timer1_init();
sys_timer2_init();
sys_wdog_init();
clr_wdg();
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void sys_timer0_init(void)
{
TMOD &= 0xF0;
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=0x00; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x00;
//EA=1; //总中断打开 等最后一个中断打开
//ET0=1; //定时器中断打开
TF0=0; //定时器标志清零
TR0=0; //定时器开关打开
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void sys_timer1_init(void)
{
TMOD |= 0x20; //使用模式2,
TH1=0x05; //给定初值,这里使用定时器最大值从5开始计数一直到255溢出
TL1=0x00;
//EA=1; //总中断打开
//ET1=1; //定时器中断打开
//TR1=1; //定时器开关打开
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void sys_timer2_init(void)
{
RCAP2H = 0/256;//
RCAP2L = 0/256;
//ET2=1; //打开定时器中断
//EA=1; //打开总中断
//TR2=1; //打开定时器开关
}
/**
* @brief 定时器0设置计数器值
* @param Value,要设置的计数器值,范围:0~65535
* @retval 无
*/
void timer0_set(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
/**
* @brief 定时器0获取计数器值
* @param 无
* @retval 计数器值,范围:0~65535
*/
unsigned int timer0_get(void)
{
return ((TH0<<8)|TL0);
}
/**
* @brief 定时器0启动停止控制
* @param Flag 启动停止标志,1为启动,0为停止
* @retval 无
*/
void timer0_run(unsigned char Flag)
{
TR0=Flag;
}
void sys_wdog_init(void)
{
//WDT_CONTR = 0x35;
}
void clr_wdg(void)
{
//WDT_CONTR = 0x35;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1
{
TH0=0x00; //重新赋值
TL0=0x00;
//sys_led_test1(); //流水灯操作
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3
{
//sys_led_test1(); //流水灯操作
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer2_isr(void) interrupt 5//定时器2中断
{
TF2=0;
//sys_led_test1(); //流水灯操作
}
//c51_timer.h文件
#ifndef __C51_TIMER_H__
#define __C51_TIMER_H__
extern void timer0_set(unsigned int Value);
extern unsigned int timer0_get(void);
extern void timer0_run(unsigned char Flag);
extern void sys_timer_init(void);
extern void sys_timer0_init(void);
extern void Timer0_isr(void);
extern void sys_timer1_init(void);
extern void Timer1_isr(void);
extern void sys_timer2_init(void);
extern void Timer2_isr(void);
extern void sys_wdog_init(void);
extern void clr_wdg(void);
#endif
3.3 数码管显示程序
实现数码管显示遥控器的发送码。
//c51_ledtube.c文件
#include "includes.h"
// 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,\
0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F
///********************************************************
//函数名称:sys_ledtube_on1
//函数功能:点亮一个数码管全为亮起来
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//void sys_ledtube_on1(void)
//{
// //根据原理图,将P0口全部输出高电平,P2选择0号数码管
// P0=0xFF;//取显示数据,段码
// P2=0; //取位码
//}
///********************************************************
//函数名称:sys_ledtube_on2
//函数功能:显示一组数据
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//static unsigned char ledtube_cnt = 0;
//void sys_ledtube_on2(void)
//{
// ledtube_cnt++;
// if(ledtube_cnt>7)
// {
// ledtube_cnt = 0;
// }
// P0 = 0x00; //防止切换数码管瞬间有虚影出现
// P2 = 0x00;
// P0 = EL[ledtube_cnt]; //取显示数据,段码
// P2 = ledtube_cnt; //取位码
//
// //根据人眼适应虚影缓冲时间为50ms左右
// //我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
// delay(100);
//}
/********************************************************
函数名称:sys_keynum_ledon
函数功能:显示按键数值
入口参数:按键数值
出口参数:
修 改:
内 容:
********************************************************/
void sys_keynum_ledon(unsigned char num,unsigned char pn)
{
//根据原理图,将P0口全部输出高电平,P2选择0号数码管
P0 = 0x00; //防止切换数码管瞬间有虚影出现
P2 = pn; //取位码
P0 = EL[num]; //取显示数据,段码
}
//c51_ledtube.h文件
#ifndef __C51_LEDTUBE_H__
#define __C51_LEDTUBE_H__
extern unsigned char const EL[];
//extern void sys_ledtube_on1(void);
//extern void sys_ledtube_on2(void);
extern void sys_keynum_ledon(unsigned char num,unsigned char pn);
#endif
3.4 外部中断程序
实现在有数据过来时,下降沿触发解码程序。
//c51_exit.c文件
#include "includes.h"
void sys_exit_init(void)
{
IT0=1; //边沿触发
EX0=1; //外部中断0开
IE0=0; //中断标志清零
//PX0 = 1; //中断优先级不配置
EA = 1;
//EX1=1; //外部中断1开
//IT1=0; //电平触发
//IT1=1; //边沿触发,IT1=0表示电平触发
}
/*------------------------------------------------
外部中断程序
------------------------------------------------*/
void Exit0_isr(void) interrupt 0
{
IE0=0; //中断标志清零
sys_nec_test();
}
/*------------------------------------------------
外部中断程序
------------------------------------------------*/
void Exit1_isr(void) interrupt 2
{
//在此处可以添加去抖动程序,防止按键抖动造成错误
//P1=~P1;
}
//c51_exit.h文件
#ifndef __C51_EXIT_H__
#define __C51_EXIT_H__
extern void sys_exit_init(void);
extern void Exit0_isr(void);
extern void Exit1_isr(void);
#endif
3.5 串口打印程序
实现printf打印不同的字符串。
//c51_uart.c文件
#include "includes.h"
/*-----------------------------------------------
名称:串口通信
内容:连接好串口或者usb转串口至电脑,下载该程序,打开电源
打开串口调试程序,将波特率设置为9600,无奇偶校验
晶振11.0592MHz,发送和接收使用的格式相同,如都使用
字符型格式,在发送框输入 hello,I Love MCU ,在接
收框中同样可以看到相同字符,说明设置和通信正确
------------------------------------------------*/
/******************************************************************/
void sys_uart_init(void)
{
SCON = 0x50; /* SCON: 模式 1, 8-bit UART, 使能接收 */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xFD; /* TH1: reload value for 9600 baud @ 11.0592MHz */
TR1 = 1; /* TR1: timer 1 run */
EA = 1; /*打开总中断*/
//ES = 1; /*打开串口中断*///当使用串口协议通讯时可以使用此型号中断
}
void Uart_SendChar(unsigned char dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
char putchar(char c)//重定向
{
Uart_SendChar(c);
return c;
}
/******************************************************************/
/* 串口中断程序 */
/******************************************************************/
static unsigned char uart_temp = 0; //定义临时变量
static unsigned char uart_cnt = 0; //定义临时变量
void UART_isr(void) interrupt 4 //串行中断服务程序
{
if(RI) //判断是接收中断产生
{
RI=0; //标志位清零
uart_temp=SBUF; //读入缓冲区的值
if(uart_cnt==0)
{
if(0x02 == uart_temp)
{
uart_cnt = 1;
}
else
{
uart_cnt = 0;
}
}
else if(uart_cnt==1)
{
if(0x05 == uart_temp)
{
uart_cnt = 2;
}
else
{
uart_cnt = 0;
}
}
else if(uart_cnt==2)
{
uart_cnt = 0;
//P1=uart_temp; //把值输出到P1口,用于观察
SBUF=uart_temp; //把接收到的值再发回电脑端
}
else
{
uart_cnt = 0;
}
}
if(TI) //如果是发送标志位,清零
{
TI=0;
}
}
//c51_uart.h文件
#ifndef __C51_UART_H__
#define __C51_UART_H__
extern void Uart_SendChar(unsigned char dat);
extern char putchar(char c);//重定向
extern void sys_uart_init(void);
extern void UART_isr(void);
#endif
3.6 步进电机程序
//“c51_28byj48.c” 文件
#include "includes.h"
bit byj48_type = 0;
unsigned int byj48_value = 0;
(1)单4拍控制方式
脉冲电平循环发送的方式控制:
//unsigned char code F_Rotation[4]={0x02,0x04,0x08,0x10}; //正转表格,换算成二进制 0000 0010,0000 0100,0000 1000,0001 0000
//unsigned char code B_Rotation[4]={0x10,0x08,0x04,0x02}; //反转表格,换算成二进制 0001 0000,0000 1000,0000 0100,0000 0010
//(2)双4拍控制方式
//AC互补,BD互补的方式进行控制:
//脉冲电平循环发送的方式控制:
unsigned char code F_Rotation[4]={0x09,0x03,0x06,0x0C}; //正转表格
unsigned char code B_Rotation[4]={0x0C,0x06,0x03,0x09}; //反转表格
(3)8拍控制方式
正转的步进次序如下:AB组 → BC组 → CD组 → DA组(每个脉冲使电机正转5.625/64度)。
反转的步进次序如下:AB组 → AD组 → CD组 → CB组(每个脉冲使电机正转5.625/64度)。
//unsigned char code F_Rotation[4]={0x03,0x06,0x0c, 0x09}; //正转表格
//unsigned char code B_Rotation[4]={0x03,0x09,0x0c,0x06};//反转表格
void sys_28byj48_func(bit type,unsigned int value)
{
unsigned char i = 0;
if(type)
{
for(i=0;i<4;i++) //4相
{
P1=F_Rotation[i]; //输出对应的相 可以自行换成反转表格
delay(value); //改变这个参数可以调整电机转速 ,数字越小,转速越大
}
}
else
{
for(i=0;i<4;i++) //4相
{
P1=B_Rotation[i]; //输出对应的相 可以自行换成反转表格
delay(value); //改变这个参数可以调整电机转速 ,数字越小,转速越大
}
}
}
//c51_28byj48.h文件
#ifndef __C51_28BYJ48_H__
#define __C51_28BYJ48_H__
extern bit byj48_type;
extern unsigned int byj48_value;
extern void sys_28byj48_func(bit type,unsigned int value);
#endif
3.7 演示效果
(1)串口打印效果
(2)步进电机实物链接图
4 设计总结
这种基于STC89C52的遥控器控制步进电机转速和转向操作并通过printf打印信息的系统可以在许多实际场景中发挥作用。以下是一些可能的应用场景:
- 智能家居系统:通过遥控器控制步进电机来控制家居窗帘、门禁系统、智能灯光等,实现智能家居的自动化和远程控制。
- 监控摄像头:控制监控摄像头的方向和转速,实现对特定区域的监控和跟踪,通过遥控器实现方向控制。
- 无人机:控制无人机的方向和高度调整,通过遥控器控制飞行器的移动和姿态调整。
- 工业自动化:控制工业机器人的运动,包括转向和速度,用于自动化生产线上的操作。
- 车载设备:应用于车载电动窗、天窗、座椅等部件的控制,通过遥控器实现车内设备的远程操作。
- 教育示范:用于教学示范,展示遥控器对步进电机的控制原理,以及如何通过单片机实现远程控制。
- 科研实验:在实验室环境中用于控制实验设备的转向和速度,如旋转式台盘、转动平台等。
- 娱乐设备:应用于模型车、模型船等遥控玩具的控制,实现远程控制玩具车辆的转向和速度。
以上是一些可能的应用场景,这种系统可以在很多需要远程控制步进电机的场合发挥作用。根据具体需求和场景的不同,系统可能需要进行适当的定制和调整。希望这些应用场景能够启发您,为您的项目提供一些灵感。如果您有任何进一步的问题或需要更多帮助,请随时告诉我。