OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4068|回复: 4

用单片机同时测量外接输入电压及流量信号,程序部分?

[复制链接]

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
126
金钱
126
注册时间
2016-5-9
在线时间
12 小时
发表于 2016-7-5 11:28:18 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 cjf1018 于 2016-7-5 11:30 编辑

怎么添加一个流量测量的代码?[mw_shl_code=c,true]//程序测量电压在外部ADC输入并打印,结果通过UART终端串口读出。 
#include <c8051f020.h>                 // 特殊寄存器的声明
#include <stdio.h>                     
//-----------------------------------------------------------------------------
// 特殊功能寄存器配置地址
//-----------------------------------------------------------------------------
sfr16 ADC0     = 0xbe;                 //16位SFR数据位地址为0xBE
sfr16 RCAP2    = 0xca;                 //当定时器2被配置为捕捉方式时寄存器地址,RCAP2L寄存器捕捉定时器2的低字节。
                                       //当定时器2被配置为自动重装方式时,它保存重载值的低字节。
sfr16 RCAP3    = 0x92;                 //定时器3被配置为自动重装时寄存器地址,该寄存器保存重载值的低字节
sfr16 TMR2     = 0xcc;                 //定时器2低字节地址
sfr16 TMR3     = 0x94;                 //定时器3低字节地址

sbit LED = P1^6;                       //LED='1' 亮灯
sbit SW1 = P3^7;                       //SW1='0' 开关闭合
long Result;                           //定义变量类型为long型
//-----------------------------------------------------------------------------
// 定义全局变量
//-----------------------------------------------------------------------------
#define BAUDRATE     115200            // 设置UART波特率
#define SYSCLK       22118400          // 外部晶振频率,开发板上的晶振
#define SAMPLE_RATE  50000             // 设置ADC0的采样率Hz。依据ADC0转换速率最高100ksps,因此最大采样率为100 000hz设置.
#define INT_DEC      256               // 过采样取平均值的次数。由过采样去平均值可提高ADC0的分辨率
#define SAR_CLK      2500000           // 理想的SAR时钟速度
#define SAMPLE_DELAY 50                // 采样延时50ms

//-----------------------------------------------------------------------------
// 函数原型
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void);           
void PORT_Init (void);
void UART0_Init (void);
void ADC0_Init (void);
void TIMER3_Init (int counts);
void ADC0_ISR (void);
void Wait_MS (unsigned int ms);

//-----------------------------------------------------------------------------
// 主函数
//-----------------------------------------------------------------------------
void main (void)
{
   long measurement;                   // 测量电压的单位mv

   WDTCN = 0xde;                       // 关闭看门狗
   WDTCN = 0xad;
   //初始化函数
   OSCILLATOR_Init ();                 
   PORT_Init ();                     
   UART0_Init ();                     
   TIMER3_Init (SYSCLK/SAMPLE_RATE);          
   ADC0_Init ();                       

   AD0EN = 1;                          // 打开ADC
   EA = 1;                             // 允许中断
   while (1)
   {
      EA = 0;                          // 禁止中断

      // 12-bit的 ADC通过INT_DEC求平均得到电压值.  
      // 结果存储在Result中,右对齐
      // 通过AIN 0.1口的电压计算方法式子:
      //                           Vref (mV)
      //   measurement (mV) =   --------------- * Result (bits)
      //                       (2^12)-1 (bits)

      measurement =  Result * 2430 / 4095; //电压计算结果
      EA = 1;                          // 重启中断
      printf("AIN0.1 voltage: %ld mV\n",measurement);//Keil内部函数printf打印输出电压值
      LED = ~SW1;                      // LED等的亮灭也反映了开关的情况
      Wait_MS(SAMPLE_DELAY);           // 等待50ms下一次采样
   }
}
//-----------------------------------------------------------------------------
// 子程序初始化
//-----------------------------------------------------------------------------
   // 晶振初始化
//-----------------------------------------------------------------------------
// 返回值 : None
// 参数   : None
// 初始化使用22.1184MHz晶振作为时钟源
void OSCILLATOR_Init (void)
{
   int i;                              // 定义延时计数变量 i
   OSCXCN = 0x67;                      // 启动外部晶振22.1184MHz
   for (i=0; i < 256; i++) ;           // 等待晶振启动
          while (!(OSCXCN & 0x80)) ;       // 检测晶振是否在运行,若正常工作则开始执行下面的程序
           OSCICN = 0x88;                  // 将外部晶振作为系统时钟,使能打开时钟丢失检测位。
}
//-----------------------------------------------------------------------------
// 端口初始化
//-----------------------------------------------------------------------------
// 返回值 : None
// 参数   : None
//
// 本函数用于配置crossbar和GPIO端口.
// P0.0   数字推挽方式        UART TX
// P0.1   数字   漏极开关     UART RX
// P1.6   数字   推挽方式     LED
// AIN0.1 模拟输入  (无配置需要)
//-----------------------------------------------------------------------------
void PORT_Init (void)
{
   XBR0     = 0x04;                    // Route UART0 to crossbar
   XBR2    |= 0x40;                    // 使能交叉开关,弱上电
   P0MDOUT |= 0x01;                    // 允许TX0作为推挽式输出
   P1MDOUT |= 0x40;                    // 允许LED作为推挽式输出

   P0MDOUT |= 0x01;                    // 设置 TX1 管脚为推挽式
   P1MDOUT |= 0x40;                    // 设置P1.6(LED)为推挽式

}

//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
// 返回值 : None
// 参数   : None
//
// 使用定时器1配置UART1.for <baudrate> and 8-N-1.
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
   SCON0  = 0x50;                     // SCON0: mode 1, 8-bit UART, enable RX
   TMOD   = 0x20;                     // TMOD: timer 1, mode 2, 8-bit reload
   TH1    = -(SYSCLK/BAUDRATE/16);     // 计数寄存器赋初值
   TR1    = 1;                         // 启动定时器1
   CKCON |= 0x10;                      // Timer1 uses SYSCLK as time base
   PCON  |= 0x80;                      // SMOD00 = 1,波特率发生器,波特率加倍
   TI0    = 1;                         // Indicate TX0 ready
}
void UART1_Init (void)
{
   SCON1  = 0x50;                     // SCON0: mode 1, 8-bit UART, enable RX
   TMOD   = 0x20;                     // TMOD: timer 1, mode 2, 8-bit reload
   TH1    = -(SYSCLK/BAUDRATE/16);     // 计数寄存器赋初值
   TR1    = 1;                         // 启动定时器1
   CKCON |= 0x10;                      // Timer1 uses SYSCLK as time base
   PCON  |= 0x80;                      // SMOD00 = 1,波特率发生器,波特率加倍
   TI1    = 1;                         // Indicate TX0 ready
}

//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Configure ADC0 to use Timer3 overflows as conversion source, to
// generate an interrupt on conversion complete, and to use right-justified
// output mode.  Enables ADC end of conversion interrupt. Leaves ADC disabled.
//
//-----------------------------------------------------------------------------
void ADC0_Init (void)
{

   ADC0CN = 0x04;                      // ADC0禁止,正常追踪模式,定时器3溢出时启动ADC0,ADC0寄存器数据右对齐

  // REF0CN = 0x07;                      // Enable temp sensor, on-chip VREF,
                                       // and VREF output buffer

   AMX0CF = 0x00;                      // AIN输入为单端输入 (默认情况下)

   AMX0SL = 0x01;                      // 选择AIN0.1引脚作为ADC mux输入

   ADC0CF = (SYSCLK/SAR_CLK) << 3;     // ADC转换时钟= 2.5MHz
   ADC0CF |= 0x00;                     // ADC0内部放大器增益PGA gain = 1 (默认)

   EIE2 |= 0x02;                       // 打开ADC中断,允许ADC0转换结束产生中断请求
}

//-----------------------------------------------------------------------------
// TIMER3_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   :
//   1)  int counts - calculated Timer overflow rate
//                    range is postive range of integer: 0 to 32767
//
// Configure Timer3 to auto-reload at interval specified by <counts> (no
// interrupt generated) using SYSCLK as its time base.
//
//-----------------------------------------------------------------------------
void TIMER3_Init (int counts)
{

   TMR3CN = 0x02;                      // 停止定时器3;清零TF3溢出标志位;将系统时钟作为时间基准
   RCAP3   = -counts;                  // 初始化重载值
   TMR3    = RCAP3;                    // 设置立即自动重载
   EIE2   &= ~0x01;                    // 禁止中断
   TMR3CN |= 0x04;                     //启动定时器

}

//-----------------------------------------------------------------------------
// 中断服务程序
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
// Here we take the ADC0 sample, add it to a running total <accumulator>, and
// decrement our local decimation counter <int_dec>.  When <int_dec> reaches
// zero, we post the decimated result in the global variable <Result>.
//
//-----------------------------------------------------------------------------
void ADC0_ISR (void) interrupt 15         //x*8+3=中断向量地址0x7B
{
   static unsigned int_dec=INT_DEC;    // Integrate/decimate counter
                                       // we post a new result when
                                       // int_dec = 0
   static long accumulator=0L;         // Here's where we integrate the
                                       // ADC samples
    AD0INT = 0;                         // Clear ADC conversion complete
                                       // indicator
   accumulator += ADC0;                // 读取ADC数值并累加结果
   int_dec--;                          // 更新int_dec数值,减1

   if (int_dec == 0)                   // 若int_dec为0,则输出结果
   {
      int_dec = INT_DEC;               // 重新设置计数器
      Result = accumulator >> 8;
      accumulator = 0L;                // 重新设置累加器
   }
}

//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Wait_MS
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters:
//   1) unsigned int ms - number of milliseconds of delay
//                        range is full range of integer: 0 to 65335
//
// This routine inserts a delay of <ms> milliseconds.
//
//-----------------------------------------------------------------------------
void Wait_MS(unsigned int ms)
{

   CKCON &= ~0x20;                     // use SYSCLK/12 as timebase

   RCAP2 = -(SYSCLK/1000/12);          // Timer 2 overflows at 1 kHz
   TMR2 = RCAP2;

   ET2 = 0;                            // 禁止定时器2中断
   TR2 = 1;                            // 启动定时器2

   while(ms)
   {
      TF2 = 0;                         // 清除标志位用于初始化
      while(!TF2);                     // 等待定时器溢出
      ms--;                            // 时间减少
   }
   TR2 = 0;                            // Stop Timer 2
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------[/mw_shl_code]

最佳答案

查看完整内容[请看2#楼]

要求不高的话,先读电流通道,再读电压通道就可以了。开2个通道。 要求高,就要2个ADC,同时采集(保证电流电压同时擦剂)。然后依次读取。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2016-7-5 11:28:19 | 显示全部楼层
要求不高的话,先读电流通道,再读电压通道就可以了。开2个通道。
要求高,就要2个ADC,同时采集(保证电流电压同时擦剂)。然后依次读取。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

1

主题

192

帖子

0

精华

高级会员

Rank: 4

积分
596
金钱
596
注册时间
2014-4-14
在线时间
104 小时
发表于 2016-7-5 11:40:32 | 显示全部楼层
流量信号是模拟量还是数字量?模拟量增加一路ADC采样,数字量根据格式做解码,基本原理就这样了。
回复

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
126
金钱
126
注册时间
2016-5-9
在线时间
12 小时
 楼主| 发表于 2016-7-5 13:40:17 | 显示全部楼层
翼间 发表于 2016-7-5 11:40
流量信号是模拟量还是数字量?模拟量增加一路ADC采样,数字量根据格式做解码,基本原理就这样了。

模拟量,和压力信号一样的,谢谢。问题是我现在不知道怎么在程序里增加一路ADC
回复

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
126
金钱
126
注册时间
2016-5-9
在线时间
12 小时
 楼主| 发表于 2016-7-6 09:10:13 | 显示全部楼层
自己顶一个
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 16:47

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表