2019-06-07 13:55:25 weixin_38679924 阅读数 1371
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    391 人正在学习 去看看 陈贤能

项目描述:
通过按键控制MCU输出不同占空比的PWM信号来控制舵机旋转不同角度;
同时在LCD1602实时显示当前舵机的角度。
仿真原理图如下:
在这里插入图片描述
C语言代码如下:

/*-----------------------------
FileName: Servo.h
Function:头文件
Author: Zhang Kaizhou
Date: 2019-6-7 13:52:49
------------------------------*/
#include <reg52.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
#define PERIOD 40 // 定时40次,周期为20ms
	
/*主控模块的端口定义*/
sbit angleAdd = P1^3;
sbit angleDecrease = P1^4;
sbit servoPWM = P3^1;

/*LCD1602显示模块端口定义*/
sbit lcdrs = P1^0;
sbit lcdrw = P1^1;
sbit lcden = P1^2;

/*主控模块函数声明*/
void timer0Init();
void keyScan();

/*LCD1602显示函数声明*/
void LCDInit();
void displayInit();
void display(uchar dat);
void writeCommand(uchar command);
void writeData(uchar angle);
void delay(uchar xms);
/*-----------------------------------------------------
FileName: main.c
Function: 单片机控制舵机
Description: 按键控制单片机输出不同占空比的PWM信号
控制舵机在0 ~ 360度范围内进行旋转;旋转的单位角度为45度
Author: Zhang Kaizhou
Date: 2019-6-7 13:50:21
------------------------------------------------------*/
#include "Servo.h"

uchar angle = 1; // 初始角度默认为0度
uchar count = 0; // 初始定时次数为0次

void main(){
	timer0Init();
	LCDInit();
	displayInit();
	while(1){
		keyScan();
		display(angle);
	}
}

/*定时器0初始化函数*/
void timer0Init(){
	TMOD = 0x01; // timer0 工作方式一(16位定时器)
	EA = 1; // 开全局中断
	ET0 = 1; // 开C/T0溢出中断允许
	TH0 = (65536 - 500) / 256; // 装初值(定时器0定时0.5ms,晶振12MHz)
	TL0 = (65536 - 500) % 256;
	TR0 = 1; // 启动定时器0
}

/*定时器0溢出中断服务程序*/
void timer0Service() interrupt 1{
	TH0 = (65536 - 500) / 256;
	TL0 = (65536 - 500) % 256;
	if(count < angle){
		servoPWM = 1;
	}else if(count < (PERIOD - angle)){
		servoPWM = 0;
	}
	count++;
}

/*键盘扫描函数*/
void keyScan(){
	if(!angleAdd){ // 角度加键按下
		delay(5);
		if(!angleAdd){
			if(angle < 9){ // 角度小于最大旋转角
				while(!angleAdd); // 等待按键释放
				angle++; // 角度加1
			}else{ // 角度大于等于最大旋转角
				while(!angleAdd);
				angle = 9; // 保持最大旋转角
			}
		}
	}
	if(!angleDecrease){ // 角度减键按下
		delay(5);
		if(!angleDecrease){
			if(angle > 1){ // 角度大于0度时减1个档位
				while(!angleDecrease);
				angle--;
			}else{ // 角度为0度时保持最小旋转角
				while(!angleDecrease);
				angle = 1;
			}
		}
	}
}
/*-----------------------------
FileName:display.c
Function: LCD1602显示函数
Author: Zhang Kaizhou
Date: 2019-6-7 13:52:11
------------------------------*/
#include "Servo.h"

uchar code table0[] = {"Servo Info"}; // 每行的字符数据
uchar code table1[] = {"Angle:"};
uchar code table2[][10] = {"000", "045", "090", "135", "180", "225", "270", "315", "360"};

/*初始化LCD1602的设置*/
void LCDInit(){
	lcden = 0; // 拉低使能端,准备产生使能高脉冲信号
	writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)
	writeCommand(0x0c); // 开显示,不显示光标
	writeCommand(0x06); // 写一个字符后地址指针自动加1
	writeCommand(0x01); // 显示清零,数据指针清零
}

/*LCD上电界面*/
void displayInit(){
	uchar i;
	writeCommand(0x80); // 将数据指针定位到第一行首
	for(i = 0; i < strlen(table0); i++){
		writeData(table0[i]);
		delay(5);
	}
	
	writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首
	for(i = 0; i < strlen(table1); i++){
		writeData(table1[i]);
		delay(5);
	}
}

/*LCD显示函数*/
void display(uchar angle){
	uchar i;
	writeCommand(0x80 + 0x40 + strlen(table1));
	for(i = 0; i < strlen(table2[angle - 1]); i++){
		writeData(table2[angle - 1][i]);
		delay(5);
	}
}

/*写指令函数*/
void writeCommand(uchar command){
	lcdrs = 0; // 命令选择
	lcdrw = 0;
	P0 = command;
	delay(5);
	
	lcden = 1; // 产生一个正脉冲使能信号
	delay(5);
	lcden = 0;
}

/*写数据函数*/
void writeData(uchar dat){
	lcdrs = 1; // 数据选择
	lcdrw = 0;
	P0 = dat;
	delay(5);
	
	lcden = 1;
	delay(5);
	lcden = 0;
}

/*延时函数*/
void delay(uchar xms){
	uint i, j;
	for(i = xms; i > 0; i--)
		for(j = 110; j > 0; j--);
}
2019-10-29 19:31:23 qq_45497666 阅读数 461
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    391 人正在学习 去看看 陈贤能

概述

在这篇博客中,将介绍一个基于51单片机的舵机控制系统,其可以通过矩阵按键输入角度,舵机打到预定角度,并在数码管上显示。

硬件设计

这次的小系统电路都由洞洞板搭建,主要包括51单片机最小系统,矩阵按键,数码管驱动和舵机四个部分。Protues仿真电路图如下
在这里插入图片描述

  • 数码管驱动
    仿真测试程序数码管时可以直接用IO口驱动,但是实物搭建电路需要再接驱动电路,这次选择了74HC245芯片来驱动。这款芯片使用非常简单,在驱动显示屏,做隔离芯片时应用都非常多。它有A0-A7,B0-B7两组输入输出口,可以DIR管脚选择数据传输方向,在使用时如果不需要转换传输方向可以直接将此管脚接到芯片VCC或者GND。
    在这里插入图片描述

  • 矩阵按键
    4*4的矩阵按键每一行每一列接在一个口上,通过行列扫描确定哪一个按键被按下,也就是导通。

  • 舵机
    舵机一般分为数字舵机和模拟电机。它们都由马达,减速齿轮组和控制电路组成。主要区别是数字电机有微处理器和晶振,能产生一周期为20ms,占空比为7.5%(即1.5ms高电平)的基准信号,通过输入与信号比较确定打角。而模拟电机则通过电位器产生的差分电压驱动电机正反转从而改变角度。这次选用的是SG90 180度的模拟舵机,价格低,带动一个激光头绰绰有余。通过单片机输出的周期为20ms的PWM波控制,在宽度从0.5ms到2.5ms,每一个占空比对应一个角度,示意图如下
    在这里插入图片描述

程序设计

PWM波的产生

在51单片机中,没有可以直接调用产生PWM波的底层库,需要自己用定时器写。一般产生PWM波能用两个定时器写,每一个定时器只固定拉高或者拉低,靠时间差确定周期。也可以只用一个定时器写,通过改变装载值来反复改变电平。以下详细说明用一个定时器写的方式,另外一个定时器空余出来可以实现更多功能。
一个定时器产生PWM波需要两组装载值,分别控制高低电平时间。设置一个全局变量作为中断标志位确定用哪一组装载值,拉高还是拉低电平,每一次进入中断后改变标志位的值。舵机180度对应每周期高电平时间0.5到2.5ms,可调范围2ms,用12M晶振时也就是2000个机器周期长,得到装载值与角度关系系数为11.11,取11,再加0.5ms对应的500个机器周期,就能得到角度与高电平对应值的关系。
机器周期数=角度*11+500
*周期20ms减去高电平时间就能换算出低电平对应装载值。*如果想要更精确,系数和对应值可以用浮点型,在最后计算装载值时再强制转换成整型。
把这段程序单独贴出来

 /*******************************************************
 装载值计算函数
*******************************************************/
 void zhuang(u8 jiaodu)
 {
   u16 zhuangza; //高电平对应机械周期数
   zhuangza=jiaodu*11+500;  //2000/180=11.11  
   H1=  (65536-zhuangza)/256; 
   L1 = (65536-zhuangza)%256;
   H2 = (45536+zhuangza)/256;//65535-(2000-高电平值)
   L2 = (45536+zhuangza)%256;
 }
 
/*******************************************************
定时器1中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{
 if(servoflag==0) //中断标志位
 {
 TH1 = H1; 
 TL1 = L1;   
 PWM=1;
 servoflag=1;
 }
 else if(servoflag==1)
 {
 TH1 = H2; 
 TL1 = L2;   
 PWM=0;
 servoflag=0;
 } 
}    

矩阵按键功能与数码管显示参数传递

矩阵按键前10个值分别对应0到9。10为确定键,按下后在主函数中将按键读到的几个一位数转换成角度,传给装载值计算函数,改变PWM波占空比,舵机打到对应角度。另外设计了11,12,13三个键,按下后能使舵机直接打到程序预定好的角度。相应按键功能分配在主函数中。具体程序不再赘述。
为了使输入多位数时能正确显示,让数码管的每一位固定显示个、十、百位,对应数组的四个元素,初值不显示,输入低位后,接受按键值的元素移向高位。

完整程序

#include "reg52.h"

typedef unsigned int u16;   
typedef unsigned char u8;

sbit LA=P2^4;     //数码管位选
sbit LB=P2^1;
sbit LC=P2^2;
sbit LD=P2^3;
sbit PWM=P2^5;   //PWM输出口
u8 code smgduan[17]={0x3f,0x06,0x9b,0x8f,0xA6,0xAd,0xBd,0x07,0xBf,
0xAf,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//0到9,大于9不显示
u8 f=0; 
static u8 jiaodu=0; //角度
u8 keyflag,servoflag;  //按键标志位,中断标志位
u8 H1=0xFA,L1=0x24,H2=0xB7,L2=0xBC;  //两组装载值
u16 zhuangzai;    
u8 w[4]={16,16,16,16};   //按键输入值保存数组,初值16不显示
u8 KeyValue;  //按键值
/*******************************************************
延时函数
*******************************************************/
void delay(u16 i)
{
 while(i--); 
}
/*******************************************************
定时器1初始化
*******************************************************/

void Timer1Init()
{
 TMOD|=0X10;
 
 TH1 = 0xFC; 
 TL1 = 0x18;
 ET1=1;   
 EA=1;
 TR1=1; 
}
/******************************************************
装载值计算函数
*******************************************************/
void zhuang(u8 jiaodu)
 { 
  u16 zhuangza;
 zhuangza=jiaodu*11+500;  //高电平对应值与角度换算
  H1=  (65536-zhuangza)/256; //H,L分别是装载值高、低8位
 L1 = (65536-zhuangza)%256;  //1是高电平装载值,2是低电平装载值
 H2 = (45536+zhuangza)/256;
 L2 = (45536+zhuangza)%256;
}
/*******************************************************
数码管动态扫描
*******************************************************/
void DigDisplay()    
{
 u8 i;
 for(i=0;i<4;i++)
 {
  switch(i)  
  {
   case(0):
    LA=0;LB=1;LC=1;LD=1; P0=smgduan[w[0]];break;
   case(1):
    LA=1;LB=0;LC=1;LD=1; P0=smgduan[w[1]];break;
   case(2):
    LA=1;LB=1;LC=0;LD=1; P0=smgduan[w[2]];break;
   case(3):
    LA=1;LB=1;LC=1;LD=0; P0=smgduan[w[3]];break;
  } 
  delay(10);  
  P0=0x00;
//  delay(100);   //不加亮度更高
 }
}
/*******************************************************
矩阵按键扫描
*******************************************************/
void KeyDown(void)
{
 char a=0;
 P1=0x0f;
 if(P1!=0x0f)
 {
  delay(1000);//消抖
  if(P1!=0x0f)
  { 
   keyflag=1;
   //测试列
   P1=0X0F;
   switch(P1)
   {
    case(0X0e): KeyValue=0;break;
    case(0X0d): KeyValue=1;break;
    case(0X0b): KeyValue=2;break;
    case(0X07): KeyValue=3;break;
   }
   //测试行
   P1=0XF0;
   switch(P1)
   {
    case(0Xe0): KeyValue=KeyValue;break;
    case(0Xd0): KeyValue=KeyValue+4;break;
    case(0Xb0): KeyValue=KeyValue+8;break;
    case(0X70): KeyValue=KeyValue+12;break;
   }
   while((a<50)&&(P1!=0xf0))  //松手检测
   {
    delay(1000);
    a++;
   }
  }
 }
}
/*******************************************************
主函数
*******************************************************/
void main()  
{
 u8 i=0;
 Timer1Init();  //定时器1初始化
 while(1)
 {
  DigDisplay();
  KeyDown();
  if(keyflag==1)
  {
   w[i]=KeyValue;
      i++;
   keyflag=0;
  }
  if(KeyValue==10)    //确定键
  {
   for(i=0;w[i]<10;i++)
    jiaodu=jiaodu*10+w[i];
   zhuang(jiaodu);
   jiaodu=0;
  }
  if(KeyValue==12)
  {
   zhuang(87);      //特定角度
  }
  if(KeyValue==13)
  {
   zhuang(97);
  }
   if(KeyValue==14)
  {
   zhuang(109);
  }
 }  
}
/*******************************************************
定时器中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{
 if(servoflag==0) 
 {
 TH1 = H1; 
 TL1 = L1;   
 PWM=1;
 servoflag=1;   //改变值,下次进入中断用另一组装载值
 }
 else if(servoflag==1)
 {
 TH1 = H2; 
 TL1 = L2;   
 PWM=0;
 servoflag=0;
 } 
}

外加模块

为了增加系统的趣味性,可以在舵机上安装激光头,距离一定距离放置三个目标靶,将其角度写入程序,则可以通过特定按键打靶。还可以在目标靶上增加指示电路,是激光打到靶后指示灯亮,可以通过光敏电阻的简单电路实现。

2018-06-26 22:31:20 qq_36192043 阅读数 20811
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    391 人正在学习 去看看 陈贤能

舵机简介

舵机一般由舵盘、减速齿轮组、位置反馈电位计5k、直流电机、控制电路板等。一般情况下舵机的信号线为黄色或白色,电源分4.8V和6V,分别对应不同的转矩标准。

 

PWM控制方法

PWM通过占空比来控制舵机,占空比周期T=20ms,高电平方波持续时间为0.5ms~2.5ms.对应舵机角度为:

 

 

 

对于t = 0.5ms~2.5ms 的产生,写程序时我们可以采用全局变量。让全局变量等于5~25之间,因为舵机的一个计数周期是0.1ms,这样全局变量的5~25正好就是0.5ms~2.5ms

 

PWM波产生思路:将信号管脚线初始化为低电平,然后写一个while循环,在循环中将该管脚置为为高电平,延时,再拉低为低电平,如此循环产生PWM波,以高电平产生时间来控制舵机转动角度。

注意:5mv以上的控制电压的变化就会引起电机的抖动。

 

基于单片机的控制:

 

单片机系统实现对舵机输出转角的控制,必须先完成两个任务:

 

1、产生    PWM周期信号,本设计产生一个20ms的周期信号;

 

2、脉宽的调整,即单片机模拟PWM信号的输出,并调整占空比。

 

当系统中只需要实现一个舵机的控制,采用的控制方式是改变单片机的一个定时器中断的初值,将20ms分为两次中断执行,一次短定时中断和一次长定时中断。这样既节省了硬件电路,也减少了软件开销,控制系统工作效率和控制精度都很高。

 


 具体的设计过程:例如想让舵机转向左极限的角度,它的正脉冲为2ms,则负脉冲为20ms-2ms=18ms,所以开始时在控制口发送高电平,然后设置定时器在2ms后发生中断,中断发生后,在中断程序里将控制口改为低电平,并将中断时间改为18ms,再过18ms进入下一次定时中断,再将控制口改为高电平,并将定时器初值改为2ms,等待下次中断到来,如此往复实现PWM信号输出到舵机。用修改定时器中断初值的方法巧妙形成了脉冲信号,调整时间段的宽度便可使伺服机灵活运动。

 

  为保证软件在定时中断里采集其他信号,并且使发生PWM信号的程序不影响中断程序的运行(如果这些程序所占用时间过长,有可能会发生中断程序还未结束,下次中断又到来的后果),所以需要将采集信号的函数放在长定时中断过程中执行,也就是说每经过两次中断执行一次这些程序,执行的周期还是20ms。

如果系统中需要控制几个舵机的准确转动,可以用单片机和计数器进行脉冲计数产生PWM信号。

脉冲计数可以利用51单片机的内部计数器来实现,但是从软件系统的稳定性和程序结构的合理性看,宜使用外部的计数器,还可以提高CPU的工作效率。

 


#include <reg52.h>      

#include <math.h>

typedef unsigned char uchar;

typedef unsigned int uint;

sbit  KEY1=P3^4;					//按键1

sbit  KEY2=P3^5;					//按键2

sbit PWM_OUT=P2^7;				//PWM输出口

uint PWM_Value;			//定义pwm值

uchar order=0; 

void Delay(unsigned int s);      //延时函数声明

uchar flag;									//舵机按键标志




/*延时函数*/
void Delay(unsigned int s)

{

unsigned int i;

for(i=0; i<s; i++);

for(i=0; i<s; i++);

}



/*定时器初始化*/
void Init_Timer0()        

{

TMOD=0x11;

TH0=(65536-1500)/256;

TL0=(65536-1500)%256;

EA = 1;

ET0 = 1;

TR0 = 1;

PT0=1;

}               


/*主函数*/
void main(void)

{

Delay(6000);

PWM_Value = 1500;					//pwm初值为1500



Init_Timer0();

while(1)

{

if((KEY1 ==0 )|(KEY2 ==0 ))							//按键1或按键2被按下

{

if(KEY1 ==0 )												//确认按键1被按下

{

flag = 1;												//标志位赋值1

}

if(KEY2 ==0 )									//确认按键2被按下

{

flag = 2;											//标志位赋值2

}

}

else

{

flag = 0;								//否则标志位为0

}

Delay(20);								//延时20ms

} 
}


/*****中断程序*******/
void timer0(void) interrupt 1 

{       

if(flag==1)	PWM_Value += 1;							//如果标志位1时,pwm的值加1
									
if(flag==2)	PWM_Value -= 1;							//如果标志位为2时,pwm减1





if(PWM_Value>=2500)										//如果pwm的值大于2500

PWM_Value = 2500;												//则保持在2500





if(PWM_Value<=500)											//如果pwm的值小于500

PWM_Value=500;													//则保持在500





switch(order)

{

	case 1:PWM_OUT=1;

		   TH0=(65536-PWM_Value)>>8; 

		   TL0=(uchar)(65536-PWM_Value);

		   break;                          

	case 2:PWM_OUT=0;

		   TH0=(65536-(5000-PWM_Value))>>8;    

		   TL0=(uchar)(65536-(5000-PWM_Value));

		   break;                          

	   

	
	case 3:

		   TH0=60536>>8;   

		   TL0=(uchar)60536;

		   break;

	case 4:

		   TH0=60536>>8;   

		   TL0=(uchar)60536;

		   order=0;

		   break;

default: order=0; 

		   break;

}

          order++;

}

 

2012-08-22 08:20:49 xiayufeng520 阅读数 1775
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    391 人正在学习 去看看 陈贤能

ATmega128单片机通过舵机控制板,控制多路舵机动作。舵机控制板与单片机之间数据通信的方式,采用了常见的串行通信(USART)。舵机控制板具有自动识别波特率(9600,19200,38400,57600,115200,128000自动识别)的功能。

 

舵机移动指令:

指令格式:#<num>P<pwm>.... T<time>\r\n

<num>=舵机号,范围1-32(十进制数)

<pwm>=脉冲宽度(舵机位置),范围500–2500。单位us(微秒)

<time>=移动到指定位置使用的时间,对所有舵机有效(范围:100-9999)。

\r\n = 十六进制数0x0d,0x0a(回车符),指令结束符。

例如: #8P600T1000\r\n

移动8号舵机到脉宽600us,使用时间为1000毫秒

#11P2000#30P2500T1500\r\n

移动11号舵机到脉宽2000us,移动30号舵机到脉宽2500us,使用的时间为1500毫秒,舵机移动的速度依赖于前一时刻舵机的位置决定,11号舵机和30号舵机同时到达指定位置。

下面是代码:

/****************************************************

----------------------------------------main.c-----------------------------------

****************************************************/

#include<iom128v.h>
#include<macros.h>
#include"128_USART0.h"

 

/*******************************************
函数名称: void delay_nms(uint ms)
功    能: 延时指定毫秒(8M晶振)
参    数: ms--延时的毫秒数
返 回 值: 无
/********************************************/
void delay_nms(uint ms)    
{
 uint i,j;
 for( i=0;i<ms;i++)
  for(j=0;j<1141;j++);//1141是在8MHz晶振下,仿真得到的数值
}


/*******************************************
函数名称: main
功    能: 主函数
参    数: 无
返 回 值: 无
/********************************************/
void main(void)
{
 USART0_init();
 while(1)
 {
  USAT0_send_string("#1P1056#2P2056T2500\r\n");
  delay_nms(3000);
  USAT0_send_string("#1P1722#2P1433T2500\r\n");
  delay_nms(3000);
 }
}

/************************************************

************************END*********************

************************************************/

 

/***********************************************

--------------------------------128_USART0.h-------------------------

***********************************************/

#ifndef _128_USART0_H_
#define _128_USART0_H_
/******************数据类型宏定义******************/
#define uchar  unsigned char
#define uint   unsigned int

#define fosc   8000000  //系统晶振
#define baud   9600     //波特率
/******************串口函数**********************/
void USART0_init(void);
void USART0_send_byte(uchar data);
uchar USART0_receive_byte(void);
void USAT0_send_string(char *str);

#endif

 

/************************************************

************************END*********************

************************************************/

 

/***********************************************

--------------------------------128_USART0.c-------------------------

***********************************************/

#include<iom128v.h>
#include"128_USART0.h"

/*******************************************
函数名称: uart0_init
功    能: 串口0的初始化
参    数: com
返 回 值: 无
/********************************************/
void USART0_init(void)
{
 UCSR0B=0X00;
 UCSR0A=0X00;
 UCSR0C=(1<<UCSZ01) | (1<<UCSZ00);//字符长度为:8位
 UBRR0L=(fosc/16/(baud+1))%256;   //波特率寄存器设定
 UBRR0H=(fosc/16/(baud+1))/256;
 UCSR0B=(1<<RXEN0) | (1<<TXEN0);  //接收使能,发送使能
}

/*******************************************
函数名称: USART0_send_byte
功    能: 串口0发送单字节
参    数: data--发送字符元素
返 回 值: 无
/********************************************/
void USART0_send_byte(uchar data)
{
 while(!(UCSR0A & (1<<UDRE0)));
 UDR0=data;
}

/*******************************************
函数名称: USART0_receive_byte
功    能: 串口0接收单字节
参    数: 无
返 回 值: UDR0--接收字符元素
/********************************************/
uchar USART0_receive_byte(void)
{
 while(!(UCSR0A & (1<<RXC0)));
 return (UDR0);
}

/*******************************************
函数名称: USAT0_send_string
功    能: 串口0发送字符串
参    数: str--字符串数据
返 回 值: 无
/********************************************/
void USAT0_send_string(char *str)
{
 while(*str)
 {
  USART0_send_byte(*str);
  str++;
 }
 USART0_send_byte(0X0A);//换行
 USART0_send_byte(0X0D);//回车
}

 

/************************************************

************************END*********************

************************************************/


 

2019-04-08 18:03:38 haigear 阅读数 909
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    391 人正在学习 去看看 陈贤能

在proteus中仿真arduino控制舵机,相对来说比较容易, 但控制过程中会遇到一些问题,这里简单的说一说,希望对新手有参考租用。
一、基本电路的搭建(为了观察可变电阻的值与转动角度的对应,添加一个虚拟终端)
在这里插入图片描述
当然,我们可以采用arduino板 库文件直接来绘制(参考前面的博文:《proteus下仿真arduino》),不过对于长期玩arduino的玩家来说最好熟悉用atmega328p来替代arduino的玩法,这样更省事!
这里需要注意的是,如果我们采用328P来替代,注意将ARef和AVcc置高电平,否则我们的变阻器的阻值就会出现异常(数值不会变化)。
在这里插入图片描述
二、程序代码(这里我们采用arduino的servo实例代码)

/*
 Controlling a servo position using a potentiometer (variable resistor)
 by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>

 modified on 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Knob
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int potpin = 3;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup() {
Serial.begin(9600);
pinMode(potpin,INPUT);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
 val = map(val, 0, 1024, 0, 180);     // scale it to use it with the servo (value between 0 and 180)
  Serial.println(val);
  myservo.write(val);                  // sets the servo position according to the scaled value
  delay(15);       

}

三、转动精度(默认情况下转动精度是不会很好的匹配驱动程序的,我们进行如下调节设置)
双击,打开伺服电机的设置界面:
在这里插入图片描述
minimum control pluse 调整靠近最左侧角度(如0角度)处的精度
maxinum control pulse 调整靠近最右边角度(如180角度)处的精度

这个频率实际与驱动程序中设定的频率有直接关系,但每次都修改驱动程序比较麻烦,这里就修正了这样一个值。
如果我们有兴趣修改驱动程序库,可以找一下代码。
自带的servo库默认的频率是50Hz,但是可以在它的头文件Servo.h中修改。修改下面这行即可以把PWM频率:
#define REFRESH_INTERVAL 500

经过调整,我们可以看到,精度还是基本对得起我们的辛劳的
在这里插入图片描述

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