首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Arduino的多个红外传感器的平均读出

使用Arduino的多个红外传感器的平均读出
EN

Code Review用户
提问于 2018-06-14 22:59:30
回答 1查看 62关注 0票数 4

我写了一个Arduino草图,连续读取来自多个模拟红外距离传感器的值,平均最后7个值并以毫米为单位输出。作为Arduino和嵌入式编程的新手,我相信还有很大的改进空间。任何批评都会受到高度赞赏,包括习语和内置的功能,我可以使用。

我的计划是扩展这个程序来运行基于传感器值的LED条。

代码语言:javascript
复制
#define LOOP_PERIOD_MS 10 // run loop every 10 ms
#define IR_WIN_LENGTH 7 // IR sensor moving-average window
#define IR_NUM_SENSORS 4 // Number of IR sensors, must be 1-6 and connected to the first analog pins

// Declare IR sensor functions
void ir_read_new_vals();
uint16_t ir_get_cur_mm( uint8_t sensor_i );
uint16_t ir_get_avg_mm( uint8_t sensor_i );

// Variables
unsigned long loop_start_ms = 0; // When the last loop iteration started

// Setup
void setup() {
  // Initialize serial communication
  Serial.begin(115200);
}

// Main loop: Read and print IR sensor data continuously
void loop() {
  // Limit loop frequency
  while ( millis() - loop_start_ms < LOOP_PERIOD_MS )
    delayMicroseconds(10);
  loop_start_ms = millis();
  // Print timestamp    
  Serial.print( loop_start_ms );
  // Read and print IR sensor values
  ir_read_new_vals();
  for ( uint8_t sensor_i = 0; sensor_i < IR_NUM_SENSORS; sensor_i++ ) {
    Serial.print(",");
    Serial.print(ir_get_avg_mm(sensor_i));
  }
  // print new line
  Serial.println("");
}


// IR sensor functions

uint8_t ir_i = IR_WIN_LENGTH; // array index for the last read value
uint16_t ir_vals_mm[IR_NUM_SENSORS][IR_WIN_LENGTH]; // "rolling" stored values for sensors
bool ir_avg_is_valid = false; // whether moving-average window is filled

// Read, scale and store values from analog sensors
// The four sensors are connected to analog pins 0, 1, 2, 3
void ir_read_new_vals() {

  // Increment "rolling array" index
  ir_i = ( ir_i + 1 ) % IR_WIN_LENGTH;

  // Read each sensor
  for ( uint8_t sensor_i = 0; sensor_i < IR_NUM_SENSORS; sensor_i++ ) {
    // Dummy sensor read (suggested when switching ADC pin)
    analogRead(sensor_i);
    // Read sensor value (values 0..1023 corresponds to 0..5V)
    uint32_t raw = analogRead(sensor_i);
    // Clamp values to 5-80cm 
    if ( raw > 600 )
      raw = 600;
    if ( raw < 80 )
      raw = 80;
    // Rescale value to mm according to datasheet curve and store
    ir_vals_mm[sensor_i][ir_i] = (uint16_t)( 67870 / ( raw - 3 ) - 40 );
  }

  // Check if the moving-average window was filled
  if ( ! ir_avg_is_valid && ir_i == IR_WIN_LENGTH - 1 )
    ir_avg_is_valid = true;
}

// Return last read sensor value in mm
uint16_t ir_get_cur_mm( uint8_t sensor_i ) {
  return ir_vals_mm[sensor_i][ir_i];
}

// Return moving average of sensor values
uint16_t ir_get_avg_mm( uint8_t sensor_i ) {
  // Return 0 if not enough values
  if ( ! ir_avg_is_valid )
    return 0;
  // Sum sensor values
  uint32_t accum_mm = 0;
  for ( uint8_t i = 0; i < IR_WIN_LENGTH; i++ )
    accum_mm += ir_vals_mm[sensor_i][i];
  // Divide and return
  return accum_mm / IR_WIN_LENGTH;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-06-15 00:41:58

  • 代码被高估了。我看到的唯一有价值的注释是//虚拟传感器读取(建议在切换ADC引脚时),但即使是这样,也应该引用数据表中的适当位置。其他的一切都可以(而且应该)用正确的名字来处理。不要害羞地将代码块分解成函数,即使只是为了给它们命名。
  • 代码不知道(或关心)连接到引脚的传感器的性质。重要的是它是IR吗?如果是射频、声纳或其他什么东西,会有什么改变吗?因此,ir_前缀似乎是一种纯粹的噪音。我强烈建议放弃它。
  • 代码确实关注信号的后处理(夹紧和重标)。对于所使用的部件,此操作非常具体。如果您可能会选择另一个部分,您将需要修复程序的核心。我强烈建议将此功能考虑到函数中,通过指针调用。
  • 我不支持像ir_avg_is_valid这样的变量。它只切换一次,但会在整个程序生命周期中消耗周期。考虑在循环之外填充第一个IR_WIN_LENGTH示例。

尽管如此,代码应该按照

代码语言:javascript
复制
    void read_new_values(uint32_t (*postproc)(uint32_t raw))
    {
        for (uint8_t sensor_i = 0; sensor_i < IR_NUM_SENSORS; sensor_i++ ) {
            uint32_t raw = read_sensor(sensor_i);
            uint32_t cooked = postproc(raw);
            values[sensor_i][win_ix] = cooked;
            win_ix = (win_ix + 1) % WIN_LENGTH;
       }
    }

    uint32_t read_sensor(uint8_t pin) {
        analogRead(pin); // Dummy read, see datasheet, chapter and verse
        return analogRead(pin);
    }

    uint32_t whatever_part_number_postproc(uint32_t value) {
        // See datasheet, chapter and verse
        clamp
        return rescale
    }

    void prefill_window(uint8_t win_size) {
        for (win_ix = 0; win_ix < win_size; win_ix++) {
            read_new_values(whatever_part_number_postproc);
        }
    }

    void setup() {
        ....
        prefill_window(WIN_LENGTH);
    }

    void loop() {
        ....
        read_new_values(whatever_part_number_postproc);
        ....
    }
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/196518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档