████工学院微机原理(3级)项目报告项目名称:微机原理课程设计项目题目:无刷直流风扇调速与测速指导教师:███系别:机电系专业:机械设计制造及其自动化组员信息学号:姓名:王██组员信息学号:姓名:郭██完成时间:2014 年12 月01 日至 2016 年 1 月 3 日成绩:评阅人:目录一、学习目标 (1)二、项目要求 (1)三、转速测量和调节系统的硬件构成 (1)四、程序流程图并说明方案思路 (3)五、风扇转速与占空比之间的关系表格和曲线 (4)六、设计程序 (5)七、分析设计过程出现的问题 (12)八、方案总结 (13)一、学习目标本次系统作业的目的在于:①通过脉冲宽度调节实现无刷直流风扇转速的改变;②借助风扇转动时产生的脉冲信号,测量风扇的转速并显示;③比较每组风扇从某一转速(600r/min)到另一转速(2000r/min)稳定运转的所需要的时间。
通过比较试验结果的估算结果并讨论结果差异的主要原因,让学生展示对无刷直流风扇数学模型建立和调节方法局限性有深入理解。
二、项目要求检查项目要求转速显示风扇转速能够显示在LED上,转速单位是r/min,刷新周期为1秒钟左右风扇转速可调风扇转速可以改变,根据要求转速在700-1400r/min风扇转速与显示通过简单方法给风扇加负载,随着转速的下降应该看到转速变化的显示转速指令输入环节通过串口或键盘输入给定转速给定某一转速,1200-1500之间,看显示转速的稳定性转速调节功能在稳定转动条件下1500r/min,在30cm处加载一个外加一个风扇,对照加载前后的稳态转速回答问题随机提出有关转速测量、PWM输出和转速控制方面的问题,要有针对性,检查设计过程中的付出。
三、系统硬件构成风扇电路:接线:黄线接Vcc,黑线接地,绿线接P3^2,蓝线接P2^5。
输出:OC输出,如下图四、画程序流程图并说明方案思路开始初始化中断产生PWM波显示转速和占空比查询是否需要反馈调整查询是否收到串口数据查询风扇转速是否更新查询有无按键操作调整占空比更新目标转速刷新数码管缓存数据计算需要的占空比YYYYNNNN程序主要用查询法判断需要执行的操作,并且利用中断处理函数来产生各种对应的标志位来通知主循环,在主循环中进行要求的运算。
其中T0定时约500us,它的每次中断相当于输出一个载波脉冲,实际上是用载波脉冲数为200个,载波周期为500us的方式构成周期为100ms的PWM波。
T1用做波特率发生器。
T2定时60ms。
每次T2中断能重置一次按键处理标志位,这个标志位能保证每60ms内只允许处理一次按键操作,让按键处理既能高速增减,也能准确;此外当有合计25次T2的中断发生时,它能保存当前的转速值并且通知主循环刷新数码管显示请况,因此我们计算转速的方式是“统计1.5s内风扇的转动圈数”。
利用在T2中断的定时判断,也能把当前数码管的显示请况发回PC机。
串口通讯方面,也是利用一个标志位来申明是否接受了数据。
使用“操作符+操作数据”的5字节字符串数据格式,例如用“A0980”代表需要风扇按n=980r/min的速度运行。
通知标志被主循环检测到的时候,会将串口数据检查并且保存成整数形式,方便后续函数的调用。
当串口数据不合理时,会发送信息到PC机。
五、风扇转速与占空比之间的关系表格和曲线编程实现单片机给PC定时发送转速与占空比数据后,取对应的数据制表如下。
将500个转速与占空比数据拟合成关系曲线如下可以发现,在风扇正常转动时,转速与占空比有着正相关的关系,占空比越大,风扇的转速越高。
此外,当占空比小于26%时,风扇停转。
六、设计程序1、主程序:#include <reg52.h>#define jingzhen 11059200UL /*使用11.0592M晶体*/#define botelv 9600UL /*波特率定义为9600*/volatile unsigned char sending;sbit dula =P2^6; //段选信号的锁存器控制sbit wela =P2^7; //位选信号的锁存器控制sbit PwmOut=P2^5; //PWM输出位置蓝线sbit need_steady=P3^4; //接地后开始调整sbit HideValue =P3^5; //接地后显示目标转速sbit K3 =P3^6; //增加占空比按钮sbit K4 =P3^7; //减少占空比按钮unsigned char code wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//数码管各位的码表unsigned char code duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0-9的码表unsigned char SPEED,SPEED_temp,count_time,count_send,wait;unsigned char PWM_count,PWM_turn,PWM_max; //控制PWM波的计数,转变值,周期个数,unsigned char Number[8]={0},value[6]={0}; //数码管显示缓存和串口字符串数据缓存int Target;bit flag=0,flag_k=0,flag_send=0,flag_direct=0; //通知标志void Timer0Init(void); //初始化函数void Timer2Init(void);void Ext0Init(void);void UARTInit(void);void check();void VALUE_To_Num(int num,unsigned char d); //数据填入数码管函数void direct(); //直接与反馈调节PWM函数void adjust();void Display();void send(unsigned char d);void sendc(unsigned char * pd);void sendc_num(unsigned char * pd);void main(){flag_direct=0;flag_send=0;wait=5;PWM_count=0,PWM_turn=170,PWM_max=200;Timer0Init();Timer2Init();Ext0Init() ;UARTInit() ;need_steady=1; //接地后开始调整HideValue =1; //接地后显示目标转速K3 =1; //增加占空比按钮K4 =1; //减少占空比按钮while(1) //主循环{if(flag_k) //控制每60ms允许通过按键调整一次PWM_turn{if(!K3&&PWM_turn<190) PWM_turn++;if(!K4&&PWM_turn>10 ) PWM_turn--;flag_k=0;}if(flag_direct){check();direct();flag_direct=0;wait=4; //传送了直接值后不能马上进行反馈调整,误差太大了}if(flag) //控制约1.5s允许调整数码管显示值{VALUE_To_Num((500*(SPEED_temp)/25),4);if(wait>0)wait--; //减缓约4.5~6s才允许反馈调整if((0==wait)&&(!need_steady)){ //满足条件时启用转速反馈调整adjust();}flag=0;}VALUE_To_Num(PWM_turn,0);if(!HideValue){ VALUE_To_Num(Target,0);} //直接按下K2显示当前的目标转速的值,可以检查有没有收到串口数据if(flag_send){ sendc_num(Number);flag_send=0;}Display();}}2、初始化子程序void Timer0Init(void){TMOD |= 0x01; //T0 16位定时TL0 = 0x33; //设置定时初值TH0 = 0xFE; //设置定时初值TF0 = 0; //清除TF0标志EA = 1; //总中断打开ET0 = 1; //定时器0中断打开TR0 = 1; //定时器0开始计时}void Timer2Init(void){RCAP2H = 0x28;RCAP2L = 0x00; //定时60msEA=1; //打开总中断ET2=1; //打开定时器2中断TR2=1; //定时器2开始计时}void ext0Init(void){INT0=1; //置高接收口P3.2PX0=1; //设置高中断优先级EA=1; //全局中断开IT0=1; //边沿触发EX0=1; //外部中断0开}void UARTInit(void) //9600bps@11.0592MHz{EA=0; //暂时关闭中断TMOD|=0x20; //定时器1工作在模式2,自动重装模式SCON=0x50; //串口工作在模式1TH1=256-jingzhen/(botelv*12*16); //计算定时器重装值TL1=256-jingzhen/(botelv*12*16);PCON|=0x80; //串口波特率加倍PS=1; //给串口中断高优先级ES=1; //串行中断允许TR1=1; //启动定时器1REN=1; //允许接收EA=1; //允许中断}3、中断操作程序/*********************************************************外部中断0统计转速脉冲*********************************************************/void ext0(void) interrupt 0 //负责统计速度值,信号下降沿产生中断{SPEED++;}/*********************************************************定时器0负责调控PWM波*********************************************************/void time0(void) interrupt 1 using 1 //负责产生PWM波{TL0 = 0x33; //设置定时初值TH0 = 0xFE; //设置定时初值PwmOut=PWM_count<PWM_turn?1:0; //计数值在0~199共200个组成;PWM_turn=0时只输出低电平,PWM_turn=PWM_max时只输出高电平PWM_count++;if(PWM_count>=PWM_max) //PWM_count达到顶端时回到初始PWM_count=0;}/*********************************************************串行中断服务函数接受速度控制命令*********************************************************/void serial() interrupt 4{static unsigned char write_point=0;static bit read_able=0;unsigned char Temp;if(RI) //判断是接收中断产生{RI=0; //标志位清零Temp=SBUF; //读入缓冲区的值if(read_able){value[write_point]=Temp;write_point++;if(write_point>4) //只读入4个字节{flag_direct=1; //通知主函数可以调节PWM了read_able=0;write_point=0;wait=4; //立即暂停反馈调整}}if(Temp=='A') //'A'作为特征码检测,也可以使用其他的字母来规定控制代码{write_point=0; //一旦收到A_ _ _ _,指针回到开头并且允许接受数据read_able=1;}}if(TI) //如果是发送标志位,清零{TI=0;sending=0; //清正在发送标志}}/*********************************************************定时器2调节数码管的刷新速度*********************************************************/void time2(void) interrupt 5 using 1 //定时器2中断{TF2=0;//必要的软件清中断标志count_time++;flag_k=1;if (count_time>=25){flag=1;SPEED_temp=SPEED;SPEED=0;count_time=0;count_send++;}if (count_send>=5){flag_send=1;count_send=0;}}4、辅助处理程序/*********************************************************检查串口数据*********************************************************/void check(){ unsigned char i;for(i=0;i<4;i++){if(value[i]<'0'||value[i]>'9')value[i]='0';}Target=(value[0]-'0')*1000+(value[1]-'0')*100+(value[2]-'0')*10+(value[3]-'0');if(Target>2180||Target<280) //禁止不可调节范围的PWMsendc("范围外的转速值!!\n");}/*********************************************************将数据填入数码管缓存*********************************************************/void VALUE_To_Num(int Num,unsigned char d){ unsigned char i;for(i=7;i>3;i--){Number[i-d]=Num%10;Num=Num/10;}}/*********************************************************直接调节PWM函数*********************************************************/void direct(){if(Target>2180||Target<280) //禁止不可调节范围的PWMreturn;if(Target<1520)PWM_turn=( 0.00003*Target*Target + 0.01311*Target + 53.467);//使用分段函数更贴合PWM-n 的关系elsePWM_turn=(-0.00009*Target*Target + 0.4299 *Target - 302.08);if(PWM_turn>200) PWM_turn=200;}/*********************************************************反馈调节PWM函数*********************************************************/void adjust(){double num;num=SPEED_temp*20;if(Target>2180||Target<280) //禁止不可调节范围的PWMreturn;if(Target<1520)PWM_turn=PWM_turn+( 0.00006*Target + 0.01311)*(Target-num);//原理是dy=f'(x)*dx else //属于比例调节PWM_turn=PWM_turn+(-0.00018*Target + 0.4299)*(Target-num);if(num<(Target/4)) //防堵转检测{ direct();wait=4;}if(PWM_turn>200) PWM_turn=200;}/*********************************************************数码管显示程序*********************************************************/void Display(){ unsigned char num;unsigned int m;for(num=0;num<8 ;num++){ P0=wei[num];wela=1;wela=0;P0=duan[Number[num]];dula=1;dula=0;for(m=128;m>0;m--); //时间间隔短,利用人眼的余辉效应,觉得每个数码管都一直在亮。