使用LPC1549的内建ADC测量电压和电流(LSSMeter)
LSSMeter = littleshrimp smart meter 哈哈
刚入围LPC1549项目时画了一个LPC1549 的外设PCB,
https://bbs.eeworld.com.cn/thread-442971-1-1.html
看起来挺高大尚的东西,当时EEWORLD-nmg同学帮我加了精华,为了不给自己太在压力,后来我让他让去掉了,因为我知道PCB是画好了,用的时候还指不定出现什么问题,有时说不定什么时候就忙了,没时间调到时候多坑人。
后来证明我的对的,在调试这些外设时很多模块都出了问题,一些直到现在也没得到解决。
还好有的外设还是比较够意思,经不住我的软磨硬泡,最后同意和我合作了,其中包括一个AD7195这个24位ADC芯片当时论坛里的一位老前辈丁丁同学给了我一些指导,让我知道差分放大器是怎么回事儿(才知道)。
LTC1999这个电流检测放大器挺好,没难为我,焊上就能用,DRV8835这个直流(步进)电机驱动芯片也挺好,也焊上就能用。
做PCB的图贴了,不发点东西也不好,虽然为了骗板骗奖品上一个小项目《LPC1500体验+使用NXP LPC1549做的一个超好玩的USB键盘 》也够我拿个小奖品的,
https://bbs.eeworld.com.cn/thread-447370-1-1.html
今天就弄个简单的东西出来,东西虽然简单,担还是挺好玩,也挺实用的。
项目中使用了LPC1549内建ADC0的两通道,一个用于直接测量电压,一个外接Linear的LTC1999高边电流检测放大器测量电流。
一、 这是什么东西
这是一个未来会非常先进的仪表,目前只实现基本电压和基本电流的测量和显示。
二、 这东西有什么用
在我们调试硬件电路的时候经常需要分析在不同情况下电路中某处电压和电流的瞬时变化(例如射频发射时的电流和电压),这时如果只使用普通万用表是肯定不行的,因为万用表的采样率一搬都非常低。而就算采样率高了,我们眼睛的速度也肯定跟不上。
所以我们需要一款仪器能够高速采集电流和电压数据,能够以图形化的方式显示下来,必要时还要能够将数据存储下来。一直以来我是比较喜欢吉时利那样的专业仪表的,也梦想着以后有钱了买几台玩玩。可现在条件不允许,买不起,就自己做一个,性能上虽然天壤之别,但基本功能还是可以保证的。
鉴于上述需求,我做了这么一个东西,他能够测量电压和电流,能将数据传送到PC,通过我用C#写的上位机程序将数据以图形化的方式显示出来,能够存储数据,还能够像示波器那样将屏幕图像保存下来用于以后分析。
三、 实现这个东西和做这个实验都用到了什么
1、 论坛发的LPC1549_LPCXpresso一块(主控制器)
2、 自己画的外设板两块(本来可以用一块,但因为其中一个板只调好了电源和其它几个模块,所以弄了两片,一片用到5V LDO,DRV8835,另一块用到LTC1999。
3、 电脑一台(运行上位机程序采集并显示数据)
4、 去电脑城花10块大洋买来的40G硬盘一块。
5、 手机充电用5V电源一个(用来通过DRV8835驱动硬盘里的音圈电机)
6、 9V电源一个,用来通过板内LCO将电压降到5V供LTC1999使用。
7、 MSP430 LaunchPad板一个(引脚输出高低电平控制音圈电机)
四、 怎么实现的这东西
1、 先裁剪LPC1549的例程,把ADC和USB CDC弄到一起。
-
- //读ADC通过串口发送
- while (1)
- {
- V = ADC0_ReadCH0();
- I = ADC0_ReadCH1();
- inBuf[0] = V>>8;
- inBuf[1] = V;
- inBuf[2] = I>>8;
- inBuf[3] = I;
- base64_encode(inBuf,outBuf,4); // loop forever
- VCOM_PrintString(outBuf);
- VCOM_PrintString("\r\n");
- delayms(1);
- }
2、 在主循环中加入读取ADC的代码将数据通过USB发到电脑虚拟串口。
3、 传输数据时用到了base64编码(C#按字串方式读一整行比较容易)
4、 上位机写一个串口接收程序,将读到的数据使用base64解码出源数据。将数据画到屏幕上显示。
-
- // Csharp 上位机代码
- g.Set(20480);//设置最大存储深度(暂无作用)用于显示历史数据
- if (serialPort.IsOpen)//如果串口已经打开
- {
- connected = false;//设置为关闭状态
- serialPort.Close();//关闭串口
- button2.Text = "连接";//更改按键文字
- }
- else
- {
- connected = true;//设置为连接状态
- g.LineSet(0, 0, Color.Red, 1f, 20, 1, 0.5f, 1024, 4096, false, false);//设置电压线
- g.LineSet(1, 0, Color.Green, 1f, 20, 1, 0.5f, 1024, 4096, false, false);//设置电流线
-
- serialPort.PortName = comboBox1.Text;//串口名为当前comboBox的本
- serialPort.BaudRate = 115200;//速率
- serialPort.DataBits = 8;//停止位
- serialPort.Parity = System.IO.Ports.Parity.None;
- serialPort.StopBits = System.IO.Ports.StopBits.One;
- serialPort.Handshake = System.IO.Ports.Handshake.None;
- //serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort_DataReceived);
- serialPort.Open();//打开串口
- button2.Text = "断开";//设置按钮文本
- new Thread((ThreadStart)delegate//开一个线程用来读串口数据(试过使用串口中断事件,速度比较慢)
- {
- while (true)
- {
- if (connected)//如果串口已经连接
- {
- try
- {
- stringBuffer += serialPort.ReadExisting();//读当前已经收到的全部数据
- stringBuffer = stringBuffer.Replace("\r", "");//去掉换行,为了使用回车符分割字串
- string[] strs = stringBuffer.Split('\n');//使用回车分割字串
- stringBuffer = strs[strs.Length - 1];//将最后一个(一搬不一定有回车符,所以不是一条完整的数据)保留,下次从此字串后边续接
- for (int i = 0; i < strs.Length - 1; i++)//遍历数据
- {
- byte[] buffer = new byte[4];//定义缓冲
- totalRxCounter++;//接收数据数量++
- string str = strs[i];//取字串
- try
- {
- buffer = Convert.FromBase64String(str);//将字串从base64解码
- int voltage = (buffer[0] << 8 | buffer[1]);//得电压数据
- int current = (buffer[2] << 8 | buffer[3]);//得电流数据
- voltages.Add(voltage);//添加电压数据到临时list
- currents.Add(current);//添加电压数据到临时list
- if (writeFile)
- {
- stream.WriteLine(string.Format("{0:D},{1:D}", voltage, current));
- stream.Flush();//输出缓冲区
- }
- validRxCounter++;
- if (validRxCounter > showCount)//如果有效数据大于1024就显示数据
- {
- validRxCounter = 0;//置零
- g.PutData(0, voltages);//添加全部电压数据
- g.PutData(1, currents);//添加全部电流数据
- double U = 3.3f / 4096.0f * voltages.Average();//求平均电压
- // currentOffset = (int)currents.Average();
- double RU = 3.3f / 4096.0f * (currents.Average() - currentOffset)/50;//检流电阻电压
- double I = RU / 0.005;
- voltages.Clear();//清临时电压缓冲
- currents.Clear();//清临时电流缓冲
- label1.BeginInvoke((ThreadStart)delegate//界面线程有效
- {
- label1.Text = string.Format("电压:{0:F3}", U);//更新电压值
- label2.Text = string.Format("电流:{0:F3}", I);//更新电流值
- label3.Text = string.Format("接收总数:{0:D},错误数量:{1:D}", totalRxCounter, errorCounter);//更新总数据和错误数据数量
- });
- if (saveImage)//如果保存图像,在刷屏前保存上一屏图像
- {
- SaveImage();//保存图像
- }
-
- g.LineSet(0, 0, Color.Red, 1f, 20, 1, 0.5f, showCount, 4096, false, false);//设置电压线
- g.LineSet(1, 0, Color.Green, 1f, 20, 1, 0.5f, showCount, 4096, false, false);//设置电流线
- g.Draw();//画线
- }
- }
- catch (Exception ex)
- {
- label3.BeginInvoke((ThreadStart)delegate
- {
- label3.Text = string.Format("接收总数:{0:D},错误数量:", totalRxCounter, errorCounter++);//更新总数据和错误数据数量
- });
-
- }
- }
- }
- catch (Exception ex)
- {
- label3.BeginInvoke((ThreadStart)delegate
- {
- label3.Text = string.Format("接收总数:{0:D},错误数量:", totalRxCounter, errorCounter++);//更新总数据和错误数据数量
- });
- }
- }
- }
-
- }).Start();//启动线程
- }
五、 实验方法
我买来一个硬盘拆掉,为了使用里边的音圈子电机做其它实验,这里用它来演示电流变化,通过LSSMeter测量这种变化并显示出来。
驱动电路我使用了TI的DRV8835这款直流电机驱动芯片,使用MSP430 LaunchPad写了一个I/O口变化的程序作为控制板。
然后将一个0.005欧的电流检测电阻串到音圈电机的电路里,使用Linear LTC1999这款高边电流检测放大器来测量检流电阻通过的电流。
再使用LPC1549的ADC测量LTC1999的输出,通过程序将电压转换成电流值。
LPC1549的另一路ADC通道接在DRV8835的输入脚,也就是MSP430 LaunchPad的I/O输出脚,这样就可以方便的知道MSP430 LaunchPad高低电平变化时音圈子电机电路中电流的变化了。
六、 视频和图片
这个视频里演示了音圈子电机的电流变化,上位机数据存储,屏幕图像保存。
这个视频演示了人体对ADC输入的干扰,和捕获到的数据。
这张图片是硬件组合后的全家福
这些图片是上位机保存的电机左右摆动时的电流,和控制脚输出电压的图象
这些图片是上位机保存的人体干扰ADC输入的图像
这张图片显示了上位机保存的数据通过EXCEL重新绘制的图形
这张图片是LTC1999的参考电路图
这张是DRV8835的参考电路图,我只使用了一个通道
七、 程序代码
这个是演示程序C#
这个是演示程序源码C#(写的很一搬,图形库我就不放了,控制类可以参考一下)
这是上位机存储的电流电压数据
这个是LPC1549的单片机程序源码
本帖最后由 littleshrimp 于 2014-9-20 17:33 编辑