资源描述
嵌入式系统课程设计(论文)
基于ARM的失重秤设计
1 失重秤介绍
失重秤,是一种间断给料连续出料的称重设备,由于失量控制是在料斗中进行,可达到较高的控制精度,结构又易于密封,故在粉料控制时与用螺旋秤来相比是一大提高。适用于水泥、石灰粉、煤粉等微细物料的控制配料。
2 设计任务及要求
1、输出为12V的直流稳压电源为传感器供电,输出为3.3V的直流电源为逻辑控制器供电
2、设计出键盘输入与显示电路(键盘显示板),用来显示当前的重量
3、将托盘的重力转换为电压输出,并对输出的差动信号放大
4、运用逻辑控制器将输出放大信号进行A/D采样,完成自动校零与自动校
满,并将重量在键盘显示板上进行显示与通过键盘显示板控制系统的运行。
3 设计方案
3.1 设计12V与3.3V稳压电源
要得到一个输出为12V的稳压电源,必须把220V的交流电经过变压器降压为16V ~ 30V的交流电压,然后接入整流桥。经过滤波以后接入12V直流稳压管,将电压输出稳定在12V,作为电桥及运放的电源。然后再将12V的输出电压接入可调电压稳压管,将输出电压调整为3.3V,作为逻辑器件的电源。
3.2 设计键盘输入与显示电路
键盘显示板的设计可以运用一般人眼的滞留时间在0.1s左右这一个生理特点,用2片8位的移位寄存器芯片串联来共同驱动两个四共阴极的LED数码显示管,一个移位寄存器芯片控制八个数码管中的位码(即:第几位点亮),另一个控制被点亮的数码管的段码(即:所显示的数)。这样每隔2ms的时间,用SPI将段码和位码发送到移位寄存器里,这样数码管所显示的数的“存活期”为2ms。当2ms以后,就应该显示下一个数码管应该显示的数字,这时通过SPI又将新的段码与位码发送到移位寄存器里。可以计算得知,八个数码管的扫描周期为16ms,完全小于人眼的分辨时间0.1s,将看到连续的数字显示在显示板上。同时,8个按键是公共端接上拉电阻,并将按键的公共端引出,作为按键按下的输入到逻辑器件的借口,按键的另一端分别接到保存数码管位码的移位寄存器引脚上。这样,相当于每隔2ms在显示数字的同时也扫描了一个按键。
3.3 设计重力感应与放大电路
将重力的变化转换为电压的变化可以采用三个压力传感器,选择三个压力传感器是为了固定托盘和更好的然每一个压力传感器都能感应到压力的变化,当重力发生变化时,每一个传感器的输出电压差发生等比例的变化,但是变化的电压及其微弱,一般小于1mv,从而必须将输出电压变化的部分用于放大电路进行放大。
信号放大部分可以使用两级放大,前一级使用运算放大器做加减差动放大,将三个传感器输出的正负信号输出端分别接入放大器的正负输入端,放大电路将把输入信号做加减运算后将传感器输出的差动电压信号进行10倍放大,后一级主要用于电压的调零于(抵消掉因为托盘的重量引起的电压输出)与放大。由于传感器输出的差动电压也会受到外部环境的影响,所以在调零时通常将最低电压调整在100mv 左右,给环境变化的影响留出100mv的余量。 这100mv 可以在后面的逻辑控制器件的程序处理时将其减去,从而减少了环境变化对测量数据的影响。将最高的输出电压定在3300mv的A/D可采样电压范围以内,以免超出A/D的采样范围影响测量。
3.4 逻辑控制器的软件实现方案
逻辑控制器件主要完成的功能是控制A/D对输入的电压进行采样并将A/D的采样值与重量的量纲相对应,运用(初始化的AD值,为放入固定重量的砝码后的AD值,为放入砝码的重量,为放入未知重物后的AD值, 为未知重物的重量)计算出托盘里面重物的重量,然后输出到键盘显示板上进行显示。
具体方案:
a、 每隔20ms通过A/D对输入的电压进行采样,在采样50次以后求出所有采样和的平均值
b、 在每次系统启动后自动进入校零和校满程序并保存,
c、 在校零和校满以后进入测量程序,根据每次采样出来的AD值运用计算公式将重量通过键盘显示板显示出来
4 器件选择
4.1 稳压电源器件的选择
采用LM7812作为电桥及放大电路的供电稳压管。
LM317是通过调节端口1的电压就可以调节输出电压的可调稳压管,因此选择将其输出调为3.3V为逻辑控制器件提供电压。
4.2 八位移位寄存器芯片与数码显示管的选择
74LS164 8位移位寄存器
四共阴极的LED数码显示管,
4.3 压力传感器与运算放大器的选择
应变片压力传感器
bLM324是四运放集成电路
4.4 逻辑控制器的选择
LPC2131是基于一个支持实时仿真和嵌入式跟踪的32/16位 ARMTTDMI-STM CPU的微控制器,并带有32KB的嵌入的高速Flash存储器。
6 软件设计
本系统软件部分的主要功能是完成对外部输入信号的AD采样,并且在对重量自校零和校满后使AD值与重量的量纲相对应,并且将所测得的重量通过SPI发送到键盘显示板上进行显示,其流程图(图10)如下:
图10 程序流程图
9 附录
9.1 总电路图
输出12V直流电压
输出3.3V直流电压
应变片压力传感器
动信号放大电路差
9.3主要程序清单
#include "config.h"
uint8 const wm[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uint8 const dm[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uint8 const M_8pai[8] = {0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09};
uint8 data_buf[8];
uint32 xs_cs=0; //需要显示的数值
uint32 ADC_Data=0;
uint8 count; //正在发送第几位段码
uint32 time_ds = 0; //定时共用变量
uint8 time_20ms_flag = 0; //定时20ms标志
uint8 time_2ms_flag = 0; //2ms定时标志
uint8 key_n=9; //保存第几号键被按下
//********************************************************************
uint8 dw0 (uint8 n) //对IO0PIN 第n位进行读操作
{
uint8 i;
if((IO0PIN&(1<<n))==0)i=0;
else i=1;
return i;
}
//********************************************************************
void DelayNS (uint32 dly) //长软件延时
{
uint32 i;
for ( ; dly>0; dly--)
for (i=0; i<5000; i++);
}
//********************************************************************
uint8 key_sm(void) //按键函数,在使用完key_n后
{ //要将key_n置为大于7的数
uint8 static key;
uint8 static key_befor=0,key_now=0,ax_flag=0;
key_befor = key_now;
key_now = dw0(3);
if((key_befor==1) && (key_now==0) && (ax_flag==0))
{
ax_flag=1;
key=count;
}
if((key_befor==1) && (key_now==1)&& (ax_flag==1) && (key==count))
{
ax_flag=0;
return key;
}
return 9;
}
//********************************************************************
void ad_int(void) //AD初始化函数
{
PINSEL1 = 1 << 28; // P0.30连接到AD0.3
/* 进行ADC模块设置 */
AD0CR = (1 << 3) | // SEL=8,选择通道3
((Fpclk / 1000000 - 1) << 8) | //转换时钟为1MHz
(0 << 16) | // BURST=0,软件控制转换操作
(0 << 17) | // CLKS=0, 使用11clock转换
(1 << 21) | // PDN=1,正常工作模式
(0 << 22) | // TEST1:0=00,正常工作模式
(1 << 24) | // START=1,直接启动ADC转换
(0 << 27); // 直接启动ADC转换时,此位无效
DelayNS(10);
ADC_Data = AD0DR; // 读取ADC结果,并清除DONE标志位
}
//********************************************************************
void bin_bcd (uint32 xs_data) //二进制转BCD码函数
{
uint32 sum;
uint8 i;
sum=xs_data;
for(i=0;i<8;i++)
{
data_buf[i] = sum%10;
sum=sum/10;
}
//****************************************************************
void timer0int(void) //定时器初始化函数
{
T0TC = 0;
T0PR = 0;
T0MCR =0x03;
T0MR0 = Fpclk/500; //定时为2ms
T0TCR = 0x01;
}
//*****************************************************************
void mspi_send(uint8 data) //spi 发送程序
{
S0PDR = data;
while((S0PSR & 0x80)==0);
}
//*****************************************************************
void __irq timer0_isr(void) //定时器0中断服务程序,发送数据
{
mspi_send(dm[data_buf[count]]); //发送段码
mspi_send(~(wm[count])); //发送位码,数码管共阴,按位取反
key_n=key_sm(); //按键返回部分
count++; //发送下一个
if(count>=8)
count=0;
time_2ms_flag = 1; //2ms定时,置1
time_ds++;
if(time_ds >= 5001) //最长定时10s
time_ds = 0;
if(time_ds % 10 == 0) //20ms定时
time_20ms_flag = 1;
T0IR = 0x01;
VICVectAddr = 0x00;
}
//*****************************************************************
void vic_timer0_int(void) //定时器0中断初始化函数
{
VICIntSelect &= ~1<<4;
VICVectCntl0 = 0x20|4;
VICVectAddr0 = (uint32)timer0_isr;
VICIntEnable |= 1<<4;
IRQEnable();
}
//*****************************************************************
void mspi_int(void) //SPI初始化函数
{
PINSEL0 = (PINSEL0 & (~(0xFF << 8))) | (0x55 << 8) ;
S0PCR = (0<<3)|
(1<<4)|
(1<<5)|
(0<<6)|
(0<<7);
S0PCCR = 10;
}
int main(void)
{
uint8 key_7_n = 0;
uint16 adc_base = 0;
uint16 adc_base_400 = 0;
uint8 adc_count = 0;
uint16 ad_data_50 = 0; //求50平均值后的AD值
uint16 zl_g = 0; //重量,单位为g
uint32 adc_data_buf = 0;
PINSEL0 &= ~(3<<6); //将p0.3设为gpio
IO0DIR &= ~(1<<3); //p0.3设为输入功能
PINSEL2 &= ~(1<<3); //选择P1.16~P1.25为GPIO功能
IO1DIR |= 0xFF<<18; //将P1.18~P1.25设为输出功能
IO1CLR |= 0xFF<<18; //输出低电平
timer0int();
vic_timer0_int();
mspi_int();
ad_int();
while(1)
{
if(time_20ms_flag == 1)
{
time_20ms_flag = 0;
if(adc_count < 50)
{
AD0CR |= 1 << 24; // 进行第一次转换
while ((ADDR & 0x80000000) == 0); // 等待转换结束
AD0CR |= 1 << 24; // 再次启动转换
while ((AD0DR & 0x80000000) == 0); // 等待转换结束
ADC_Data = AD0DR; // 读取ADC结果
ADC_Data = (ADC_Data >> 6) & 0x3ff;
ADC_Data = ADC_Data * 2480; // 参考电压经过3/4分压
ADC_Data = ADC_Data / 1024;
adc_data_buf += ADC_Data;
adc_count++;
}
else
{
adc_count = 0;
ad_data_50=adc_data_buf/50;
adc_data_buf = 0;
}
}
if(key_n == 0)
{
key_n = 9;
key_7_n++;
if(key_7_n == 1) //按下第一次记下AD基数
adc_base = ad_data_50;
if(key_7_n == 2)
{
adc_base_400 = ad_data_50; //按下第二次,记下AD
key_7_n = 0;
break;
}
}
xs_cs = ad_data_50 + key_7_n*10000;
bin_bcd(xs_cs);
}
while(1)
{
if(time_20ms_flag == 1)
{
time_20ms_flag = 0;
if(adc_count < 50)
{
AD0CR |= 1 << 24; // 进行第一次转换
while ((ADDR & 0x80000000) == 0); // 等待转换结束
AD0CR |= 1 << 24; // 再次启动转换
while ((AD0DR & 0x80000000) == 0); // 等待转换结束
ADC_Data = AD0DR; // 读取ADC结果
ADC_Data = (ADC_Data >> 6) & 0x3ff;
ADC_Data = ADC_Data * 2480; // 参考电压经过3/4分压
ADC_Data = ADC_Data / 1024;
adc_data_buf += ADC_Data;
adc_count++;
}
else
{
adc_count = 0;
ad_data_50=adc_data_buf/50;
if(ad_data_50 >= adc_base)
zl_g = (ad_data_50-adc_base)*400/(adc_base_400 - adc_base);
adc_data_buf = 0;
}
}
xs_cs = zl_g;
bin_bcd(xs_cs);
}
return 0;
}
第 13 页 共 13 页
展开阅读全文