单片机控制舵机

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

/*-----------------------------
FileName: Servo.h
Function:头文件
Author: Zhang Kaizhou
Date: 2019-6-7 13:52:49
------------------------------*/
#include 
#include 
#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--);
}

你可能感兴趣的:(C51)