/*
* Title: Servo Controller for DC Motors
* Author: Osama Mazhar
* Date: 28th December 2013
* Email: osamazhar@yahoo.com
*/
#include <reg51.h>
#define KEYPAD P1
#define ldata P0
sbit rs = P3^5;
sbit rw = P3^6;
sbit en = P3^7;
sbit busy = P0^7;
sbit Clock = P3^0;
sbit Status = P3^1;
void lcdready();
void lcdcmd(unsigned char);
void lcddata(unsigned char);
void MSDelay(unsigned int);
unsigned char KeypadRead();
unsigned int GetInput();
void inttoLCD(unsigned int);
unsigned char code keypad[4][4] = {'7','8','9','/','4','5','6','X','1','2','3','-','.','0','=','+'};
unsigned int cnt;
void Encoderpulse() interrupt 0
{
cnt++;
}
void main()
{
unsigned int actual_position, previous_error;
unsigned char dt;
float Ki, Kp, I, Prop, D, Kd, error, setpoint, PWM;
Status = 0;
KEYPAD = 0xF0; // make higher bits of keypad port that is column bits input and low row bits outputs
P2 = 0x00;
Clock = 0;
lcdcmd(0x38); // 2 lines and 5X7 matrix
lcdcmd(0x0C); // Display ON, Cursor Blinking = 0x0E But this command is Display ON, Cursor OFF
lcdcmd(0x01); // Clear Display Screen
lcdcmd(0x80); // Force Cursor to the beginning of the First Line
lcdcmd(0x06);
IE = 0x81;
TCON = 0x01;
setpoint = GetInput();
I = 0;
dt = 5;
Ki = 0.00001;
Kp = 5;
Kd = 1;
error = 0;
while(1) //2 MC
{
actual_position = cnt;
previous_error = error;
error = setpoint - actual_position;
/**********Propotional Controller*************/
Prop = Kp * ((error * 255) / setpoint);
//this error value is actually whats determining how much PWM should the controller generate.
//this is being divided by variable "setpoint" and multiplied by 255 inorder to scale the max
//PWM to 255. As the other controller generating PWM works on the range of 0-255 for PWM.
//For faster response increase Kp and for smaller use smaller Kp
if(Prop > 255)
Prop = 255;
// For max speed, when Kp is increase and fast response is required, max PWM is set until the
// error value becomes so small that it forces Prop/PWM to be less than 255 following actual PID graph.
else if(Prop < 1)
goto Stop;
// this prevents Prop to become negative as Prop is a float variable, this will ultimately forces
// controller to an undetermined condition. So this is the solution :p
/***************Integral Controller**************/
MSDelay(dt);
I = I + Ki * error * dt;
/**********Differential Controller*************/
D = Kd * (error - previous_error) / dt;
lcdcmd(0xC0); // for development purposes
inttoLCD(PWM); // same
inttoLCD(cnt); // same
PWM = Prop + I + D;
if(PWM > 255)
PWM = 255;
P2 = PWM; // transfering the value of PWM to other controller
}
// stop routine when the target value is achieved by the Propotional Controller
// this routine may change when Integral and Derivative controllers will be implemented.
Stop: lcdcmd(0xC0);
Prop = 0;
inttoLCD(Prop);
P2 = 0;
while(1);
} // main braces
unsigned int GetInput()
{
unsigned char L, cnt, Key[5];
unsigned int Entry = 0;
cnt = 0;
do
{
Re: Key[cnt] = KeypadRead();
L = Key[cnt];
if(L == '+' | L == '-') // my beloved sryinge pump routine to re-enter data if mistakenly entered wrong
goto Re;
if(L == '=')
continue;
lcddata(Key[cnt]);
Key[cnt] = Key[cnt] - 48;
cnt++;
}
while(L != '=' & cnt != 5);
switch(cnt)
{
case(1):
{
Entry = Key[0];
break;
}
case(2):
{
Entry = (Key[0] * 10) + Key[1];
break;
}
case(3):
{
Entry = (Key[0] * 100) + (Key[1] * 10) + Key[2];
break;
}
case(4):
{
Entry = (Key[0] * 1000) + (Key[1] * 100) + (Key[2] * 10) + Key[3];
break;
}
case(5):
{
Entry = (Key[0] * 10000) + (Key[1] * 1000) + (Key[2] * 100) + (Key[3] * 10) + Key[4];
break;
}
}
return Entry;
}
void inttoLCD(unsigned int value)
{
unsigned int x, y, z, d[5];
char l;
x = value / 10; // => 6553
d[0] = (value % 10) + 48; // => 6 (LSD) *
d[1] = (x % 10) + 48; // => 3 *
y = x / 10; // => 655
d[2] = (y % 10) + 48; // => 5 *
z = y / 10; // => 65
d[3] = (z % 10) + 48; // => 5 *
d[4] = (z / 10) + 48; // => 6 (MSD) *
if(d[4] == 48 & d[3] == 48 & d[2] == 48 & d[1] == 48)
{
lcddata(d[0]);
for(l=0; l<4; l++)
lcddata(' ');
}
if(d[4] == 48 & d[3] == 48 & d[2] == 48 & d[1] != 48)
{
for(l=1; l>=0; l--)
lcddata(d[l]);
for(l=0; l<3; l++)
lcddata(' ');
}
if(d[4] == 48 & d[3] == 48 & d[2] != 48)
{
for(l=2; l>=0; l--)
lcddata(d[l]);
for(l=0; l<2; l++)
lcddata(' ');
}
if(d[4] == 48 & d[3] != 48)
{
for(l=3; l>=0; l--)
lcddata(d[l]);
lcddata(' ');
}
if(d[4] != 48)
{
for(l=4; l>=0; l--)
lcddata(d[l]);
}
}
void MSDelay(unsigned int count)
{
unsigned int i;
while(count)
{
i = 122;
while(i>0)
i--;
count--;
}
}
void lcdready()
{
busy = 1; // make the busy pin an input
rs = 0;
rw = 1;
while(busy == 1) // wait here for busy flag
{
en = 0; // strobe the enable pin
MSDelay(1);
en = 1;
}
return;
}
void lcdcmd(unsigned char value)
{
lcdready();
ldata = value;
rs = 0;
rw = 0;
en = 1;
MSDelay(1);
en = 0;
return;
}
void lcddata(unsigned char value)
{
lcdready();
ldata = value;
rs = 1;
rw = 0;
en = 1;
MSDelay(1);
en = 0;
return;
}
unsigned char KeypadRead()
{
unsigned char colloc, rowloc;
do
{
KEYPAD = 0xF0; // ground all rows at once
colloc = KEYPAD; // read the port for columns
colloc &= 0xF0; // mask row bits
}
while(colloc != 0xF0); // check until all keys are released
do
{
do
{
MSDelay(8); // call delay
colloc = KEYPAD; // see if any key is pressed
colloc &= 0xF0; // mask unsused bits
}
while(colloc == 0xF0); // keep checking for keypress
MSDelay(8); // call delay for debounce
colloc = KEYPAD; // read columns
colloc &= 0xF0; // mask unused bits
}
while(colloc == 0xF0); // wait for keypress
while(1)
{
KEYPAD &= 0xF0; // masking row bits
KEYPAD |= 0x0E; // now ground row 0 0E = 00001110b ORing won't affect column data
colloc = KEYPAD; // read columns
colloc &= 0xF0; // mask row bits
if(colloc != 0xF0) // column detected
{
rowloc = 0; // save row location
break;
}
KEYPAD &= 0xF0;
KEYPAD |= 0x0D; // ground row 1 0D = 00001101b ORing won't affect column data
colloc = KEYPAD; // read columns
colloc &= 0xF0; // mask row bits
if(colloc != 0xF0) // column detected
{
rowloc = 1; // save row location
break;
}
KEYPAD &= 0XF0;
KEYPAD |= 0x0B; // ground row 2 0B = 00001011b
colloc = KEYPAD; // read columns
colloc &= 0xF0; // mask row bits
if(colloc != 0xF0) // column detected
{
rowloc = 2; // save row location
break;
}
KEYPAD &= 0XF0;
KEYPAD |= 0x07; // ground row 3 07 = 00000111b
colloc = KEYPAD; // read columns
colloc &= 0xF0; // mask row bits
if(colloc != 0xF0) // column detected
rowloc = 3; // save row location
break;
}
// check columns and send result to LCD
if(colloc == 0xE0) //0E = 00001110
return keypad[rowloc][0];
else if(colloc == 0xD0) //0D = 00001101
return keypad[rowloc][1];
else if(colloc == 0xB0) //0B = 00001011
return keypad[rowloc][2];
else
return keypad[rowloc][3];
}
没有合适的资源?快使用搜索试试~ 我知道了~
基于51单片机的PID直流电机、PID无刷直流电机精准位置控制系统(源代码+仿真工程)
共9个文件
png:2个
hex:2个
workspace:1个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 201 浏览量
2024-02-06
10:31:37
上传
评论
收藏 243KB 7Z 举报
温馨提示
基于51单片机的PID直流电机、PID无刷直流电机精准位置控制系统(源代码+仿真工程) 本课题旨在实现比例积分微分(PID)控制器对直流电机的位置控制。一个光的或磁的反馈编码器被假定附着在电机的轴上。 编码器脉冲被馈送到主微控制器,主微控制器根据电流和电机的期望位置(脉冲)制定误差,并使用PID控制器计算脉冲宽度数据输出。 然后,这个脉宽数据被馈送到从控制器,从控制器生成一个2KHz的波,计算脉宽并从主控制器馈送。这就是如何控制电机的速度,直到顺利地达到所需的位置。 这在实践中是一个修改的PID,其中比例,积分和导数常数调整,使电机输出没有超调情况。欢迎提出进一步的建议和改进。
资源推荐
资源详情
资源评论
收起资源包目录
基于51单片机的PID直流电机、PID无刷直流电机精准位置控制系统(源代码+仿真工程).7z (9个子文件)
Kiel uVision Project Files
Slave (PWM) Controller
Slave (PWM).hex 1014B
Main Controller
Main PID with LCD-Keypad.hex 8KB
Main PID with LCD-Keypad.uvproj 14KB
Main PID with LCD-Keypad.c 8KB
未命名1678083280.png 189KB
未命名1678083468.png 194KB
Proteus File
Servo Basic 89C51 LCD Keypad.pdsprj.DESKTOP-7FSAA6I.Eric.workspace 3KB
Project Backups
Servo Basic 89C51 LCD Keypad.DSN 148KB
Servo Basic 89C51 LCD Keypad.pdsprj 27KB
共 9 条
- 1
资源评论
cqtianxingkeji
- 粉丝: 3038
- 资源: 1631
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功