【51单片机练习2——可变电阻ADC数模转换+LCD12864显示】

任务需求

2018年安徽省机器人大赛单片机与嵌入式系统应用技能竞赛试题

  1. 使用可变电阻通过AD(10位)数模转换输入3位半数值(保留两位小数),模拟超声波传感器输入0-10米
  2. 模拟输入值大于1.2米的时候,输出控制电机正转,并实现数值越大转速越快,数值越小,转速越慢的效果。当小于0.9米的时候电机反转,小于0.5米的时候开始声光报警。

硬件介绍

1.可变电阻、AD转换

在本实验中,可变电阻与单片机的P1.0口连接,电路原理图如下所示:
可变电阻原理图
在本实训平台所使用的是STC15W4K56S4单片机,其所属的15系列都有其内部的AD转换器。该内部A/D转换器可支持8路A/D采集,支持8位或10位的A/D分辨率,转换速度可达300KHz。

与A/D相关的寄存器配置

1.1 P1ASF P1口模拟功能控制寄存器

P1ASF模拟功能控制寄存器的配置用于确认P1的哪一个口与电位器相连接
P1ASF寄存器

1.2 ADC_CONTR:ADC控制寄存器

ADC_CONTR寄存器为ADC的主要寄存器,在该寄存器中配置ADC的电源、模数转换器速度、模数转换开启以及停止和模拟输入通道选择等相关配置。
该寄存器的相关介绍如下所示:
ADC控制寄存器
ADC_POWER:ADC电源控制位配置详解:
ADC_POWER
SPEED1、SPEED0:模数转换器转换速度控制位详解:

SPEED1SPEED0A/D转换所需时间
1190个时钟周期转换一次,CPU工作频率21MHz时,A/D转换速度约300KHz
10180个时钟周期转换一次
01360个时钟周期转换一次
00540个时钟周期转换一次

ADC_FLAG标志位详解:
模数转换器转换停止标志位,当AD转换结束后,ADC_FLAG = 1,要由软件清0。
不管A/D转换完成后由该位申请产生中断,还是由软件查询该标志位A/D转化是否结束,A/D转换完成后该位置1,一定要软件清零!!!

ADC_START标志位详解:
该位为模数转换器转换启动控制位,设置为“1”开始转换,转换结束后自动为“0”

CHS2、CHS1、CHS0模拟输入通道选择位详解:

CHS2CHS1CHS0模拟通道输入选择
000P1.0作为A/D输入
001P1.1作为A/D输入
010P1.2作为A/D输入
011P1.3作为A/D输入
100P1.4作为A/D输入
101P1.5作为A/D输入
110P1.6作为A/D输入
111P1.7作为A/D输入
1.3 ADC_RES、ADC_RESL:A/D转换结果寄存器

A/D转换结果

2.步进电机

步进电机的驱动原理图如下所示:
步进电机驱动原理
步进电机就是能够通过输入脉冲的个数确定旋转的角位移。
步进电机由驱动芯片ULN2003驱动,利用ULN2003与单片机的引脚连接以驱动步进电机,需要注意的是,要驱动步进电机需要放大驱动电流。
引脚连接:

ULN2003单片机引脚号
ULN_O1P11
ULN_O2P12
ULN_O3P13
ULN_O4P14

硬件连接示意图

各元器件与MCU的引脚连接可以参照下图:
硬件连接示意图

软件流程图

软件流程图

功能实现

需求1:可变电阻通过AD(10位)数模转换输入3位半数值(保留两位小数),模拟超声波传感器输入0-10米

实现步骤

  1. 获取ADC获取的结果
unsigned int GetADCResult(unsigned char ch)                             
{ 
    unsigned int Vo;
    P1ASF = 0x01;                                        //选择P1口的哪一口 这里的口和ch要对应才能达到选择该口
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;//0x00|0x00|ch|0x08:选择A/D输入通道,开始A/D转换 
                                                         // 这么用语句的主要原因就是不能位寻址
                                                         //   通道选择在后3位所以直接用一个整数表示ch
                                                         //例如ch=6 那么对应的后三位就是110           
    _nop_();                             //Must wait before inquiry , 
    _nop_();                             //设置ADC_CONTR寄存器后需加4个CPU时钟周期的延时,才能保证值被写入ADC_CONTR寄存器 
    _nop_(); 
    _nop_(); 
    while (!(ADC_CONTR & ADC_FLAG));     //Wait complete flag 

   ADC_CONTR &= ~ADC_FLAG;               //Close ADC 将标志位清零等待下次硬件置1
                                         //也可以写成 ADC_CONTR= ADC_CONTR & ( ~ADC_FLAG)
   //Vo=(ADC_RES<<2)+ADC_RESL; 			 //打开10位AD采集功能   如果用8位AD Vo=ADC_RESL 即可
     Vo=(ADC_RES<<2); 	                 //10位AD采集 即2的10次方 满值为1024 这里用1024表示5伏的电压 
										 //8位AD采集 即 2的8次方  满值为256  用256表示5伏
    return Vo; 
}
  1. 记录电位器模拟输入的最大值和最小值,由于其是线性变换,可以等效缩放到0-10这个范围。
ad=GetADCResult(0);			 //读取电压数量值P1.0口  采集AD电压值
num = (ad - 336)/67.6 * 100;	//将获取到的值等效缩放到 0~10 具体问题具体分析
serial_one_send_string("AD距离:");
// 设置两位有效小数 以下输出为串口输出测试
serial_one_send_number(num / 1000 % 10);
serial_one_send_number(num / 100 % 10);
serial_one_send_string(".");
serial_one_send_number(num / 10 % 10);
serial_one_send_number(num / 1 % 10);
serial_one_send_string("米\r\n");			
serial_one_send_number(KeyNum);
serial_one_send_string("\r\n");
  1. LCD12864显示
    与上一篇显示超声波距离数值相同,不再赘述。

需求2: 模拟输入值大于1.2米的时候,输出控制电机正转,并实现数值越大转速越快,数值越小,转速越慢的效果。当小于0.9米的时候电机反转,小于0.5米的时候开始声光报警。

实现步骤:

  1. 设置步进电机正转以及反转的设置
uchar phasecw[4] ={0x10,0x08,0x04,0x02};//反转 电机导通相序 D-C-B-A
uchar phaseccw[4]={0x02,0x04,0x08,0x10};//正转 电机导通相序 A-B-C-D

//ms延时函数
void Delay_xms(uint x)
{
 uint i,j;
 for(i=0;i<x;i++)
  for(j=0;j<224;j++);
}

//顺时针转动
void MotorCCW(uchar speed)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phaseccw[i];
   Delay_xms(150 - speed);//转速调节
  }
}

//逆时针转动
void MotorCW(void)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phasecw[i];
   Delay_xms(50);//转速调节
  }
}

//停止转动
void MotorStop(void)
{
 MotorData=0x00;
}
  1. 不断进行比较,看模拟输入值符合哪个场景,执行对应操作
if(num > 120)
{
    int i;
	i=1000-c;
	count = 0 ;
	timer_count = 0 ;											     
	//电机正转
	MotorCCW(num);    //将num值作为速度参数传入,实现模拟输入越大转速越快
					  //模拟输入越小,转速越小
}											
if(num<90)
{
	//电机反转
	MotorCW(); 
}
if(num<50)
{														
	LED0=~LED0;
	BEEP_IO = ~BEEP_IO;
	delay(200);
}

总结:

经过这个练习之后,对串口调试输出的重要性有的不一般的理解,由于该实训平台所使用的STC15W4K56S4单片机不支持在线debug,因此只能直接烧录程序看现象是否符合预期。
但天不遂人愿,每次烧录结束后的结局都不是我想要的,但一时间也不知道是哪里出现了问题,比如在读取电位器模拟输入并在LCD12864上显示,屏幕上只有固定文字,丝毫不显示数据,完全不清楚是因为没有数据产生没显示还是现实的方式有问题。因此这时候就需要串口数据传输,辅助程序debug,获取的数据值先从串口打印输出,看是不是正确,再将数据交给显示屏显示。
以上就是本次练习的小小总结,我是王平凡,一个单片机小白,如有建议或疑问,欢迎留言(建议欢迎!疑问恕我菜鸡不一定能一一回答)。

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值