首先认识一下电位器和舵机如下图
如何通过电位器控制舵机,让舵机随着电位器的旋转而跟着转动呢,整个思路是这样的,先采集电位器的信号,然后通过类比信号输出PWM来控制舵机的转动,下面我们来进行第一步,采集电位器信号。 /以下是采集电位器过程*************/
我们要采集电位器信号首先要认识XPT2046,如下图 我们可以看到他有四个模式配置管脚(P34–P37)和四个采集通道(AIN0–AIN3),具体的工作方式很复杂,要了解的话要查阅对应的手册,而我们要用它的话其实不用这么麻烦,只要会配置让他读出并且返回电位器的值就行了,下面直接上程序 XPT2026.c文件 #include <REGX52.H> #include <INTRINS.H>
//引脚定义 sbit XPY2046_DIN=P3^4; sbit XPY2046_CS=P3^5; sbit XPY2046_DCLK=P3^6; sbit XPY2046_DOUT=P3^7;
/**
- @brief ZPT2046读取AD值
- @param Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数
- @retval AD转换后的数字量,范围:8位为0255,12位为04095
*/ unsigned int XPT2046_ReadAD(unsigned char Command) { unsigned char i; unsigned int Data=0; XPY2046_DCLK=0; XPY2046_CS=0; for(i=0;i<8;i++) { XPY2046_DIN=Command&(0x80>>i); XPY2046_DCLK=1; XPY2046_DCLK=0; } for(i=0;i<16;i++) { XPY2046_DCLK=1; XPY2046_DCLK=0; if(XPY2046_DOUT){Data|=(0x8000>>i);} } XPY2046_CS=1; // if(Command&0x08) // { return Data>>8; // } // // else // { // return Data>>4; // }
}
XPT2026.h文件 #ifndef XPT2046_H #define XPT2046_H
#define XPT2046_VBAT 0xAC #define XPT2046_AUX 0xEC #define XPT2046_XP 0x9C //0xBC #define XPT2046_YP 0xDC
#define XPT2046_VBAT_16 0xA4 #define XPT2046_AUX_16 0xE4 #define XPT2046_XP_16 0x94 //0xBC #define XPT2046_YP_16 0xD4
unsigned int XPT2046_ReadAD(unsigned char Command);
#endif
以上我们就配置好了XPT2046,还配置好了12位的哦,而我们今天用的是读取的是8位
继续 配置好了怎么用?接下来写main.c文件 #include <REGX52.H> #include “Delay.h” #include “LCD1602.h” #include “XPT2046.h”
sbit LED1=P2^2; sbit beep=P2^5; sbit DA=P2^1; sbit pwm=P1^0;
unsigned int ADValue,ADValue1,ADValue2,ADValue4; unsigned char Counter,Compare;
void main(void) { Timer0_Init(); LCD_Init(); LCD_ShowString(1,1,“ADJ NTC GR”); while(1) { ADValue=XPT2046_ReadAD(XPT2046_XP); //读取AIN0,可调电阻 ADValue4=6+(ADValue/20); LCD_ShowNum(2,1,ADValue,3); //显示AIN0 ADValue1=XPT2046_ReadAD(XPT2046_YP); //读取AIN1,热敏电阻 LCD_ShowNum(2,6,ADValue1,3); //显示AIN1 ADValue2=XPT2046_ReadAD(XPT2046_VBAT); //读取AIN2,光敏电阻 LCD_ShowNum(2,11,ADValue2,3); //显示AIN2 Delay(100); if(ADValue2>150) { LED1=1; } else { LED1=0; } if(ADValue1>=140) { beep=1; } else { beep=0; }
}
}
void Timer0_Routine() interrupt 1 { TL0 = 0x9C; //设置定时初值 TH0 = 0xFF; //设置定时初值 Counter++; Counter%=255; //计数值变化范围限制在0~99
if(Counter<ADValue) //计数值小于比较值
{
DA=1; //输出1
}
else //计数值大于比较值
{
DA=0; //输出0
}
if(Counter<ADValue4) //计数值小于比较值
{
pwm=1; //输出1
}
else //计数值大于比较值
{
pwm=0; //输出0
}
}
由于我们使用了定时器,接下来配置定时器Timer0.c文件 #include <REGX52.H>
/**
- @brief 定时器0初始化,100us@12.000MHz
- @param 无
- @retval 无
*/ void Timer0_Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x9C; //设置定时初值 TH0 = 0xFF; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; }
/*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x9C; //设置定时初值 TH0 = 0xFF; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0;
}
} */
Timer0.h文件 #ifndef TIMER0_H #define TIMER0_H
void Timer0_Init(void);
#endif
还有延时函数文件Delay.c文件
void Delay(unsigned int xms) { unsigned char i, j; while(xms–) { i = 2; j = 239; do { while (–j); } while (–i); } }
Delay.h文件 #ifndef DELAY_H #define DELAY_H
void Delay(unsigned int xms);
#endif
然后,最后的最后,,相信大家都看到了我们用了LCD1602显示模块,,哈哈哈,那我们继续 LCD1602.c文件 #include <REGX52.H>
//引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0
//函数定义: /**
-
@brief LCD1602延时函数,12MHz调用可延时1ms -
@param 无 -
@retval 无 */ void LCD_Delay() { unsigned char i, j; i = 2; j = 239; do { while (–j); } while (–i); }
/**
- @brief LCD1602写命令
- @param Command 要写入的命令
- @retval 无
*/ void LCD_WriteCommand(unsigned char Command) { LCD_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); }
/**
- @brief LCD1602写数据
- @param Data 要写入的数据
- @retval 无
*/ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); }
/**
- @brief LCD1602设置光标位置
- @param Line 行位置,范围:1~2
- @param Column 列位置,范围:1~16
- @retval 无
*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } }
/**
- @brief LCD1602初始化函数
- @param 无
- @retval 无
/ void LCD_Init() { LCD_WriteCommand(0x38);//八位数据接口,两行显示,57点阵 LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关 LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动 LCD_WriteCommand(0x01);//光标复位,清屏 }
/**
- @brief 在LCD1602指定位置上显示一个字符
- @param Line 行位置,范围:1~2
- @param Column 列位置,范围:1~16
- @param Char 要显示的字符
- @retval 无
*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) { LCD_SetCursor(Line,Column); LCD_WriteData(Char); }
/**
- @brief 在LCD1602指定位置开始显示所给字符串
- @param Line 起始行位置,范围:1~2
- @param Column 起始列位置,范围:1~16
- @param String 要显示的字符串
- @retval 无
*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) { unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!=’\0’;i++) { LCD_WriteData(String[i]); } }
/**
- @brief 返回值=X的Y次方
/ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;i++) { Result=X; } return Result; }
/**
- @brief 在LCD1602指定位置开始显示所给数字
- @param Line 起始行位置,范围:1~2
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~65535
- @param Length 要显示数字的长度,范围:1~5
- @retval 无
*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i–) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+‘0’); } }
/**
- @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
- @param Line 起始行位置,范围:1~2
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:-32768~32767
- @param Length 要显示数字的长度,范围:1~5
- @retval 无
*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) { unsigned char i; unsigned int Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData(’+’); Number1=Number; } else { LCD_WriteData(’-’); Number1=-Number; } for(i=Length;i>0;i–) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+‘0’); } }
/**
- @brief 在LCD1602指定位置开始以十六进制显示所给数字
- @param Line 起始行位置,范围:1~2
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~0xFFFF
- @param Length 要显示数字的长度,范围:1~4
- @retval 无
*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i,SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i–) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+‘0’); } else { LCD_WriteData(SingleNumber-10+‘A’); } } }
/**
- @brief 在LCD1602指定位置开始以二进制显示所给数字
- @param Line 起始行位置,范围:1~2
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~1111 1111 1111 1111
- @param Length 要显示数字的长度,范围:1~16
- @retval 无
*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i–) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+‘0’); } }
LCD1602.h文件 #ifndef LCD1602_H #define LCD1602_H
//用户调用函数: void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif
哈哈哈说好的采集电位器信号一不小心把代码放完了
都是代码模块,只要简历对应的文件然后把代码放进去就可以了,如果实在弄不了的可以私信我邮箱或者评论,我看到了会发源文件给你。大家相互帮助哈
至此,所有的代码都已经放出来了,其实这个代码里面包括了。。。天黑亮灯,温度报警。。还有电位器控制LED亮度,,,都在里面,是一个大杂烩。。。。代码很粗糙哈哈哈,也懒得完善了,电位器转动时,舵机跟着转动的动作还是不是很流畅,其实可以做的更细致一点,可以把读取8位变成读取12位,这样动作会细致很多,有兴趣的可以加油试试。
对了,不会舵机接线的可以看程序,我的信号线接在了P10上面
|