【TI 技术资料分享】+ 基于launchpad的简易数字万用表

2019-07-28 19:10发布

本帖最后由 dirtwillfly 于 2015-1-23 22:08 编辑

一:本设计基于MSP430G2231为核心控制系统,结合适量的硬件设计,配合12864液晶,制作出一个自动量程的电压,电阻,温度测试仪表。电压量程在0-11V,电阻档量程:0-100kΩ,温度适于室温测量。此表多适用于电子DIY爱好者使用。
二:原理
图片1.png

当被测电压VDD时,由上图可知,我们只需测出V值,即可知道VDD值。VDD=V*(R9+R10)/R10.V的值可用430ADC采集得到。
2. 电阻测量:
图片2.png
原理和电压测量一样当VDD已知,R10已知,V已知时。R9的阻值:R9=(VDD/V-1)*R103:温度测量:基于18B20DS1820 数字温度计以9 位数字量的形式反映器件的温度值。DS1820 通过一个单线接口发送或接收信息,因此在中央微处理器和DS1820 之间仅需一条连接线(加上地线)。用于读写和温度转换的电源可以从数据线本身获得,无需外部电源。因为每个 DS1820 都有一个独特的片序列号,所以多只DS1820 可以同时连在一根单线总线上,这样就可以把温度传感器放在许多不同的地方。这一特性在HVAC 环境控制、探测建筑物、仪器或机器的温度以及过程监测和控制等方面非常有用。整体设计思路
图片3.png
三:电路实现 图片4.png
1:电阻与电压测量外围硬件电路图,电压测量时,高电位端接红表笔,低电位端接黑表笔。通过运放的电压跟随,解决了数字万用表仅使用于测量恒压源的窘境,但同时也由于运放的限制,测量电压范围变小。当测量电压低于2V时,ADC0采集的电压值有效,作为测量值,而ADC1采样无效。每次测量都是由大量程开始,通过程序判断,该量程是否合适,如量程太大,进行小量程切换。 2:电阻的测量是本设计的经典,不借助于模拟开关,手动开关选档。而借助于单片机IO口的上拉输出,高阻态输入完成自动选档。如当P12为高电平时,P13为高阻态时,R5与被测电阻形成通路分IO口电压,然后再经358跟随供AD采集。通过切换P12P13的输入输出状态即可实现档位切换。 图片5.png
图片6.png
18B20具有很多优秀的特性,如零待机功耗,独特的单线接口仅需一个端口引脚进行通讯,报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件。3:电源模块    因为用的是MSP430LAUNCHPAD开发板,故3,5V供电电压不用单独制作。只需产生运放需要要的12V电压,本设计依赖34063的芯片的升压,由5V升到12V 图片7.png
4:液晶显示模块 图片8.png
此设计也是经典之举,尽管抬高了此作品的造价,因430总共只有10个可操控IO口,而一般的显示模块都得用8个左右,而用12864的串行模式,同时运用MSP430SPI通信,既方便又高效的完成了液晶显示的操作。同时采用5分钟定时息屏操作,从根本上解决了低功耗的问题,环保,节约。关于12864这里不再赘述。 4:按键模块 图片9.png
因为设计温度是一直显示,所以就只需对电阻,电压进行选择。所以运用了两个按键作为人际交互手段,而复位按键由MSP430开发板自身提供。实物图 图片10.jpg
源码:
  1. /*
  2. * main.c
  3. */
  4. #include <msp430.h>
  5. typedef struct REG{
  6. unsigned bit0 : 1;
  7. unsigned bit1 : 1;
  8. unsigned bit2 : 1;
  9. unsigned bit3 : 1;
  10. unsigned bit4 : 1;
  11. unsigned bit5 : 1;
  12. unsigned bit6 : 1;
  13. unsigned bit7 : 1;
  14. }REG;
  15. typedef enum STATE{
  16. WELCOME = 1,
  17. VOLTAGE,
  18. RESISTANCE
  19. }STATE;
  20. #define uchar unsigned char
  21. #define uint  unsigned int
  22. #define jump_ROM 0xCC
  23. #define start 0x44
  24. #define read_EEROM 0xBE
  25. typedef unsigned char byte;
  26. typedef unsigned int word;
  27. #define N_SAMPLE 12
  28. #define P1 ((REG *) 0x0021)
  29. #define RS P1->bit7
  30. #define DQ P1->bit4           //DS18B20数据口
  31. void dispnum(unsigned int a,unsigned char x,unsigned char y) ;
  32. void dispuserset(unsigned int a,unsigned char x,unsigned char y);
  33. volatile STATE state = WELCOME;
  34. word adc_value[N_SAMPLE];
  35. unsigned char TMPH,TMPL;
  36. void Key_Init(void)
  37. {
  38. P2SEL &= ~BIT6 + ~BIT7;
  39. P2REN |= BIT6 + BIT7;
  40. P2OUT |= BIT6 + BIT7;
  41. P2IE |= BIT6 + BIT7;
  42. P2IES |= BIT6 + BIT7;
  43. P2IFG &= ~BIT6 + ~BIT7;
  44. }
  45. void TimerA0_Init(void)
  46. {
  47. TACCR0 = 30000;
  48. TACCR1 = 20000;
  49. TACTL = TASSEL_2 + MC_2 + ID_3;
  50. TACCTL1 = CCIE;
  51. TACTL |= TACLR;
  52. }
  53. void ADC_Init(void)
  54. {
  55. ADC10CTL1 = CONSEQ_2;
  56. ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
  57. ADC10DTC1 = N_SAMPLE;
  58. ADC10SA = (word) adc_value;
  59. }
  60. void ADC_Channel_Select(word channel)
  61. {
  62. ADC10CTL1 &= 0x0fff;
  63. ADC10CTL1 |= channel;
  64. ADC10AE0 &= 0x00;
  65. ADC10AE0 = (1 << (channel >> 12));
  66. }


  67. inline void SPI_Init(void)
  68. {
  69. USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE;
  70. USICTL1 |= USICKPH + USIIE;
  71. USICKCTL = USIDIV_4 + USISSEL_2;
  72. USICTL0 &= ~USISWRST;
  73. __enable_interrupt();
  74. }
  75. void SPI_Transmit(byte data)
  76. {
  77. USISRL = data;
  78. USICNT = 8;
  79. // while (!(USIIFG & USICTL1));
  80. LPM0;
  81. }
  82. /********************************************************************
  83. * 名称 : delay()
  84. * 功能 : 延时函数
  85. * 输入 : 无
  86. * 输出 : 无
  87. ***********************************************************************/
  88. void delay(unsigned int yN)
  89. {
  90. unsigned int i;
  91. for(i=0; i<yN; i++)
  92.       ;
  93. }
  94. /********************************************************************
  95. * 名称 : Reset()
  96. * 功能 : 复位DS18B20
  97. * 输入 : 无
  98. * 输出 : 无
  99. ***********************************************************************/
  100. uchar Reset(void)
  101. {
  102. uchar deceive_ready;
  103. DQ = 0;
  104. delay(29);
  105. DQ = 1;
  106. delay(3);
  107. deceive_ready = DQ;
  108. delay(25);
  109. return(deceive_ready);
  110. }
  111. /********************************************************************
  112. * 名称 : read_bit()
  113. * 功能 : 从DS18B20读一个位值
  114. * 输入 : 无
  115. * 输出 : 从DS18B20读出的一个位值
  116. ***********************************************************************/
  117. uchar read_bit(void)
  118. {
  119. uchar i;
  120. DQ = 0;
  121. DQ = 1;
  122. for(i=0; i<3; i++);
  123. return(DQ);
  124. }
  125. /********************************************************************
  126. * 名称 : write_bit()
  127. * 功能 : 向DS18B20写一位
  128. * 输入 : bitval(要对DS18B20写入的位值)
  129. * 输出 : 无
  130. ***********************************************************************/
  131. void write_bit(uchar bitval)
  132. {
  133. DQ=0;if(bitval==1)
  134. DQ=1;
  135. delay(5);
  136. DQ=1;
  137. }
  138. /********************************************************************
  139. * 名称 : read_byte()
  140. * 功能 : 从DS18B20读一个字节
  141. * 输入 : 无
  142. * 输出 : 从DS18B20读到的值
  143. ***********************************************************************/
  144. uchar read_byte(void)
  145. {
  146. uchar i,m,receive_data;
  147. m = 1;
  148. receive_data = 0;
  149. for(i=0; i<8; i++)
  150. {
  151.   if(read_bit())
  152.   {
  153.    receive_data = receive_data + (m << i);
  154.   }
  155.   delay(6);
  156. }
  157. return(receive_data);
  158. }
  159. /********************************************************************
  160. * 名称 : write_byte()
  161. * 功能 : 向DS18B20写一个字节
  162. * 输入 : val(要对DS18B20写入的命令值)
  163. * 输出 : 无
  164. ***********************************************************************/
  165. void write_byte(uchar val)
  166. {
  167. uchar i,temp;
  168. for(i=0; i<8; i++)
  169. {
  170.   temp = val >> i;
  171.   temp = temp & 0x01;
  172.   write_bit(temp);
  173.   delay(5);
  174. }
  175. }

  176. /********************************************************************
  177. * 名称 : GETDATA()
  178. * 功能 : 获取数据
  179. * 输入 : 无
  180. * 输出 : 温度值,整数
  181. ***********************************************************************/
  182. unsigned int GETDATA()
  183. {
  184. unsigned int temp;
  185.   DQ = 0;
  186.   Reset();
  187.   write_byte(jump_ROM);
  188.   write_byte(start);
  189.   Reset();
  190.   write_byte(jump_ROM);
  191.   write_byte(read_EEROM);
  192.   TMPL = read_byte();
  193.   TMPH = read_byte();
  194.   temp = TMPL>>4 + 4<<TMPH;
  195.   return temp;
  196. }
  197. void LCD_Write_Cmd(byte com)
  198. {
  199. RS = 1;
  200. SPI_Transmit(0xf8);
  201. SPI_Transmit(0xf0 & com);
  202. SPI_Transmit(0xf0 & (com << 4));
  203. RS = 0;
  204. }
  205. void LCD_Write_Dat(byte dat)
  206. {
  207. RS = 1;
  208. SPI_Transmit(0xfa);
  209. SPI_Transmit(0xf0 & dat);
  210. SPI_Transmit(0xf0 & (dat << 4));
  211. RS = 0;
  212. }
  213. void LCD_Pos(byte x, byte y)
  214. {
  215. byte pos;
  216. switch(x)
  217. {
  218. case 0:
  219.   x = 0x80;
  220.   break;
  221. case 1:
  222.   x = 0x90;
  223.   break;
  224. case 2:
  225.   x = 0x88;
  226.   break;
  227. case 3:
  228.   x = 0x98;
  229.   break;
  230. default:
  231.   break;
  232. }
  233. pos = x + y;
  234. LCD_Write_Cmd(pos);
  235. }

  236. void LCD_Init(void)
  237. {
  238. LCD_Write_Cmd(0x30);
  239. LCD_Write_Cmd(0x0c);
  240. LCD_Write_Cmd(0x01);
  241. LCD_Write_Cmd(0x02);
  242. LCD_Write_Cmd(0x80);
  243. }
  244. void LCD_Write_Str(byte x, byte y, char *str)
  245. {
  246. LCD_Pos(x, y);
  247. while (*str)
  248. {
  249.   LCD_Write_Dat(*str++);
  250. }
  251. }
  252. void LCD_Clear_Screen(void)
  253. {
  254. LCD_Write_Cmd(0x34);
  255. LCD_Write_Cmd(0x30);
  256. LCD_Write_Cmd(0x01);
  257. }
  258. void Disp_Welcome_Msg(void)
  259. {
  260. LCD_Write_Str(0, 1, "自动量程仪表");
  261. LCD_Write_Str(1, 0, "温度:   °C");
  262. LCD_Write_Str(2, 0, "1:电阻  2:电压");
  263. LCD_Write_Str(3, 0, "    欢迎使用");
  264. }
  265. word filter(void)
  266. {
  267. word ad_val;
  268. int i;
  269. for (i = 0; i < N_SAMPLE; i++)
  270. {
  271.   ad_val += adc_value[i];
  272. }
  273. ad_val /= N_SAMPLE;
  274. return ad_val;
  275. }
  276. void Measure_Voltage(void)
  277. {
  278. word ad_val = 0;
  279. byte flag=0;
  280. LCD_Write_Str(2, 0, "                ");
  281. LCD_Write_Str(2, 0, "电压:");
  282. LCD_Write_Str(3, 0, "                ");
  283. ADC_Channel_Select(INCH_1);
  284. ADC10CTL0 &= ~ENC;
  285. while (ADC10CTL1 & BUSY); // Wait if ADC core is active
  286. ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
  287. LPM0;
  288. ad_val = filter();
  289. if (ad_val > 150)
  290. {
  291.   flag=1;
  292. }
  293. else
  294. {
  295.   flag=0;
  296.   ADC_Channel_Select(INCH_2);
  297.   ADC10CTL0 |= ADC10SC;
  298.   LPM0;
  299.   ad_val = filter();
  300. }
  301. if(flag==1)
  302. {
  303.   ad_val=ad_val*1.05;
  304.   dispuserset(ad_val,3,2);
  305. }
  306. else
  307. {
  308.   ad_val=ad_val*3.60;
  309.   dispuserset(ad_val,3,2);
  310. }
  311. LCD_Write_Str(3, 4, "V");
  312. }
  313. inline void Measure_Resistance(void)
  314. {
  315. byte flag=0;
  316. word ad_val,temp_adc;
  317. LCD_Write_Str(2, 0, "                ");
  318. LCD_Write_Str(2, 0, "电阻:");
  319. LCD_Write_Str(3, 0, "                ");
  320. P1DIR |= BIT2;
  321. P1DIR &= ~BIT3;
  322. P1OUT |= BIT2;
  323. ADC_Channel_Select(INCH_0);
  324. ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
  325. LPM0;
  326. ad_val = filter();
  327. if (ad_val > 150)
  328.   {
  329.    flag=1;
  330.   }
  331.   else
  332.   {
  333.    flag=0;
  334.    P1DIR |= BIT3;
  335.    P1DIR &= ~BIT2;
  336.    P1OUT |= BIT3;
  337.    ADC_Channel_Select(INCH_0);
  338.    ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
  339.    LPM0;
  340.    ad_val = filter();
  341.   }
  342. if(flag==1)
  343. {
  344.    temp_adc=1024-ad_val;  //(带小数显示)
  345.    temp_adc=ad_val*10/temp_adc;
  346.    temp_adc=50*temp_adc;
  347.    dispuserset(temp_adc,3,2);
  348.    LCD_Write_Str(3, 4, "KOH");
  349. }
  350. else
  351. {
  352.    temp_adc=1024-ad_val;  //(整数显示)
  353.    temp_adc=ad_val*10/temp_adc;
  354.    temp_adc=100*temp_adc;
  355.    dispnum(temp_adc,3,2);
  356.    LCD_Write_Str(3, 4, "OH");
  357. }
  358. }
  359. void main(void) {
  360. WDTCTL = WDTPW + WDTHOLD;
  361. P1DIR |= BIT7 + BIT4;
  362. SPI_Init();
  363. LCD_Init();
  364. ADC_Init();
  365. Key_Init();
  366. TimerA0_Init();
  367. P1DIR |= BIT0;
  368. // Disp_Welcome_Msg();
  369. for(;;)
  370. {
  371.   switch(state)
  372.   {
  373.   case WELCOME:
  374.    Disp_Welcome_Msg();
  375.    //dispnum(GETDATA(),1,2);
  376.    break;
  377.   case RESISTANCE:
  378.    Measure_Resistance();
  379.    break;
  380.   case VOLTAGE:
  381.    Measure_Voltage();
  382.    break;
  383.   }
  384.   LPM0;
  385. }
  386. }
  387. #pragma vector = USI_VECTOR
  388. __interrupt void USI_ISR(void)
  389. {
  390. USICTL1 &= ~USIIFG;
  391. LPM0_EXIT;
  392. }
  393. #pragma vector = TIMERA1_VECTOR
  394. __interrupt void TIMERA1_ISR(void)
  395. {
  396. switch(TAIV)
  397. {
  398. case 2:
  399.   TACCR1 += 20000;
  400.   LPM0_EXIT;
  401.   break;
  402. }
  403. }
  404. #pragma vector = ADC10_VECTOR
  405. __interrupt void ADC10_ISR(void)
  406. {
  407. LPM0_EXIT;
  408. }
  409. #pragma vector = PORT2_VECTOR
  410. __interrupt void PORT2_ISR(void)
  411. {
  412. if (TACCTL0 & CCIFG)
  413. {
  414.   if (P2IFG & BIT6)
  415.   {
  416.    if (state == VOLTAGE)
  417.    {
  418.     state = WELCOME;
  419.    }
  420.    else
  421.    {
  422.     state = VOLTAGE;
  423.    }
  424.   }
  425.   if (P2IFG & BIT7)
  426.   {
  427.    if (state == RESISTANCE)
  428.    {
  429.     state = WELCOME;
  430.    }
  431.    else
  432.    {
  433.     state = RESISTANCE;
  434.    }
  435.   }
  436.   TACCTL0 &= ~CCIFG;
  437.   TACCR0 += 30000;
  438. }
  439. P2IFG &= ~BIT6 + ~BIT7;
  440. }
  441. /********************************************************************************/
  442. void dispnum(unsigned int a,unsigned char x,unsigned char y)    //整数显示(4位数-9999)
  443. {
  444. unsigned char flag,i=0;
  445. unsigned char out[5];
  446. out[0]=' ';
  447. out[1]=48+(a/1000);
  448. a=a%1000;
  449. out[2]=48+(a/100);
  450. a=a%100;
  451. out[3]=48+(a/10);
  452. out[4]=48+(a%10);
  453. flag=0;
  454. for(i=1;(i<4)&&(flag==0);i++)
  455. {
  456.   if(out[i]==48)
  457.   {
  458.    out[i]=32;
  459.   }
  460.   else
  461.   {
  462.    flag=1;
  463.   }
  464. }
  465. LCD_Pos( x, y);
  466. i=0;
  467. while (i<5)
  468. {
  469.   LCD_Write_Dat(out[i]);
  470.   i++;
  471. }
  472. }
  473. void dispuserset(unsigned int a,unsigned char x,unsigned char y)//小数显示(2位数+2位小数-99.99)
  474. {
  475. unsigned char flag,i=0;
  476. unsigned char out[5];
  477. out[0]=48+(a/1000);
  478. a=a%1000;
  479. out[1]=48+(a/1000);
  480. a=a%100;
  481. out[2]='.';
  482. out[3]=48+(a/10);
  483.     a=a%10;
  484. out[4]=48+a;
  485. flag=0;
  486. for(i=0;(i<2)&&(flag==0);i++)
  487. {
  488.   if(out[i]==48)
  489.   {
  490.    out[i]=32;
  491.   }
  492.   else
  493.   {
  494.    flag=1;
  495.   }
  496. }
  497. LCD_Pos( x, y);
  498. i=0;
  499. while (i<5)
  500. {
  501.   LCD_Write_Dat(out[i]);
  502.   i++;
  503. }
  504. }
复制代码


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
11条回答
xyz549040622
1楼-- · 2019-07-28 19:30
给灰板顶起
dirtwillfly
2楼-- · 2019-07-28 22:31
xyz549040622 发表于 2015-1-23 22:10
给灰板顶起

:handshake
youluo235
3楼-- · 2019-07-28 23:18
顶起。哈哈
acer4736
4楼-- · 2019-07-29 02:45
 精彩回答 2  元偷偷看……
jinpaidianzi
5楼-- · 2019-07-29 03:09
学习一下 争取自己做一个
teabottle
6楼-- · 2019-07-29 04:23
钥匙能有配套的机械设计就好了

一周热门 更多>