Proteus仿真:51单片机--数码管显示舵机角度值
一、仿真概述
74HC595级联控制三路数码管,显示的数字从零开始,每按下一次按键1,数码管所显示的数字逐渐累加,最大可累加至999,同时,舵机转过与数码管显示数字相同的角度。当按键2按下时,数码管显示数字与舵机角度归零。
仿真效果图:
舵机配置(角度范围:0-180度,控制精度:0.054-2):
注意:舵机配置中的控制精度仅为本人所取经验值,应根据实际情况而定。
二、代码思路
1、74HC595驱动数码
/*******************************************************************************
* 函数名 : HC595_Shift
* 函数功能 : 给74HC595 SH_CP引脚上升沿,数据移位
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void HC595_Shift()
{
HC595_SH=0; //SH_CP置低电平
_nop_(); //延时2us
_nop_();
HC595_SH=1; //SH_CP置高电平
}
/*******************************************************************************
* 函数名 : HC595_Store
* 函数功能 : 给74HC595 ST_CP引脚上升沿,数据存储
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void HC595_Store()
{
HC595_ST=0; //ST_CP置低电平
_nop_(); //延时2us
_nop_();
HC595_ST=1; //ST_CP置高电平
}
/*******************************************************************************
* 函数名 : HC595_Send_Data
* 函数功能 : 74HC595数据显示,串行输入并行输出
* 输入 : num:要显示数字的存储区地址
* 输出 : 无
*******************************************************************************/
void HC595_Send_Data(u8 *num)
{
u8 i,j;
for(i=0;i<3;i++) //三位数,遍历三次
{
for(j=0;j<8;j++) //一个段码八位,遍历八次
{
if((num[i]<<j)&0x80) //段码左移动j位,判断第j位是否为1
HC595_DS=1; //74HC595 DS引脚输出高电平
else
HC595_DS=0; //74HC595 DS引脚输出低电平
HC595_Shift(); //74HC595移位寄存器左移一位
}
}
HC595_Store(); //74HC595存储数据,并行输出给数码管显示
}
/*******************************************************************************
* 函数名 : Segment_Display
* 函数功能 : 数码管显示
* 输入 : num:要显示数字
* 输出 : 无
*******************************************************************************/
void Segment_Display(u16 num)
{
u8 tmp[3]; //临时存储变量
tmp[2]=num/1%10; //按键计数取个位数
tmp[1]=num/10%10; //按键计数取十位数
tmp[0]=num/100%10; //按键计数取百位数
smg_num[2]=smg_code[tmp[2]]; //数码管存储个位段码
smg_num[1]=smg_code[tmp[1]]; //数码管存储十位段码
smg_num[0]=smg_code[tmp[0]]; //数码管存储百位段码
HC595_Send_Data(smg_num); //74HC595并行发送三位数给数码管显示
}
2、PWM控制舵机角度
/*******************************************************************************
* 函数名 : Tim1_Init
* 函数功能 : 定时器中断1初始化
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Tim1_Init()
{
TMOD|=0x10; //工作方式1模式
TH1=0x00; //设置定时初始值
TL1=0x00;
ET1=1; //开始定时器1中断
TR1=1; //开始定时器1
EA=1; //开启总中断
}
/*******************************************************************************
* 函数名 : Tim1
* 函数功能 : 定时器中断1服务函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Tim1() interrupt 3
{
if(PWM) //判断PWM输出是否为1
{
TH1=TH_Low; //设为低电平定时装载值
TL1=TL_Low;
}
else
{
TH1=TH_High; //设为高电平定时装载值
TL1=TL_High;
}
PWM=~PWM; //PWM输出取反
}
/*******************************************************************************
* 函数名 : Servo_Set_Angle
* 函数功能 : 设置舵机角度
* 输入 : angle:舵机角度值
* 输出 : 无
*******************************************************************************/
void Servo_Set_Angle(u16 angle)
{
u16 tmp; //临时存储变量
if(angle<=0) angle=0; //角度小于等于0,置0
if(angle>=180) angle=180; //角度大于等于180,置180
//以下所指偏差仅是本人仿真测试所得经验值,应根据真实电路或其他仿真环境对这部分代码进行调试
if(angle != 0 && angle%45==0) angle=angle-5; //角度不为0且是45倍数时,减5,降低偏差
tmp=(angle*11)+45; //计算每转一度的机器周期,2000/180=11,加45,降低偏差
TH_High=(65536-tmp)/256; //高电平定时装载值
TL_High=(65536-tmp)%256;
TH_Low=(45536+tmp)/256; //低电平定时装载值
TL_Low=(45536+tmp)%256;
}
注意:以上代码仅提供基本思路