suncat0504 发表于 2022-7-27 18:47

【CuriosityNano测评报告】光强角度检测装置

本帖最后由 suncat0504 于 2022-8-4 19:10 编辑

#申请原创#
@21小跑堂
在上次测试驱动步进马达的基础上,把相关部件组装起来,装置如下图:整个装置分为两层:上层电源板提供整个电路的电源、以及光强采集用太阳能板。光强采集由一小片太阳能板完成,在明亮状态下,可以采集到0.5V左右的电压。这个电压在PIC18F57Q43的ADC的处理下,得到300左右的数值,不需要增加放大器就能处理了。电源由两个18650电池,经7805稳压后提供给主电路板。下层电路板由PIC18F57Q43评估板、步进电机驱动板、步进电机组成。因为太阳能电池板要连线到评估板上,为了避免连接线缆产生缠绕,把太阳能电池和步进电机绑定到一起,因此把步进电机倒置,让电机转动轴固定到底板上,把整个两层电路装置悬空。为了简化测试,太阳能板被固定为一个倾角,因此本次测试没有对倾角进行控制。程序处理以以下逻辑进行处理:主程序循环中:1、采集当前位置的光强电压信号,完成指定组数的ADC数据做平均值处理,这样得到的数据和最大值比较,从而得到新的最大值并保存。2、驱动电机步进一个角度,然后按照步骤1继续处理,刷新最大值。3、当太阳板完成360度的旋转后,我们得到了这一圈中光强电压最大的数据。4、在3的基础上,重新旋转,同时按照1重新获取对应位置的光电转换数据,并和3中的最大值对比,数值接近的就视为光强最大的检测角度,停止转动。主程序代码如下:// 步进电机正反转标志
extern uint8_t fb_flag;
// 预定步进数
extern uint16_t plan_step;
// 总步数(用来定位最强的位置)
volatile uint16_t step_all=0;
// ADC最大值
uint16_t adc_max=0;

/*
                         Main application
*/
void main(void) {
    // ADC转换用高、低8位数据
    uint8_t resultHigh=0;
    uint8_t resultLow=0;
    uint16_t result=0;
    double avrs;
    uint8_t idx=0;
    uint16_t avr_result=0;       // 本次采集平均值

    // Initialize the device
    SYSTEM_Initialize();

    //Setup ADC
    ADCON0bits.FM = 1; //right justify
    ADCON0bits.CS = 1; //ADCRC Clock
    ADPCH = 0x00; //指定RA0为模拟数据输入通道
    TRISAbits.TRISA0 = 1; //Set RA0 to input
    ANSELAbits.ANSELA0 = 1; //Set RA0 to analog
    ADCON0bits.ON = 1; //Turn ADC On   

    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();

    int i;
   
    // LED指示
    LED0_SetLow();
   
// 初始化动作,表明程序运转
    fb_flag=1;
    plan_step=512;
    __delay_ms(1000);
    fb_flag=2;
plan_step=512;

// LED指示
    LED0_SetHigh();
    __delay_ms(2000);

    fb_flag=0;

    // 启动转动,同时收集ADC数据
    step_all=0;
    fb_flag=1;   // 正转方式
    idx=0;
   
    // 主循环处理
    while (1) {
      // 触发ADC转换,并取得转换结果
      ADCON0bits.GO = 1; //Start conversion
      while (ADCON0bits.GO); //Wait for conversion done
      resultHigh = ADRESH; //Read result
      resultLow = ADRESL; //Read result
      // 合成为16位数据
      result=resultHigh;
      result=result*256 + resultLow;
      
      // 计算平均值,并存储
      avrs=result/ADC_AVR_CNT;
      idx=(idx+1)%ADC_AVR_CNT;
      if (idx==0) {
            // 数据初始化
            avr_result=0;
            
            // 满指定组数据了,求出平均结果
            for (i = 0; i < ADC_AVR_CNT; i++) {
               avr_result=avr_result+avrs;
            }
            if (avr_result > adc_max && step_all < STEPS_CYCLE) {
                adc_max = avr_result;
            }         
            

            if (step_all >= STEPS_CYCLE && fb_flag>0) {
                step_all=STEPS_CYCLE; // 避免累加溢出
                printf("Complete a lap.Search max.\r\n"); //
                // 超过1圈了,反转找最大值位置
                fb_flag=2;
                plan_step=STEPS_1DU;

                //if (avr_result > adc_max-10 &&avr_result < adc_max+10) {
                if (avr_result > adc_max-10) {
                  // 找到大值,停止。过指定时间之后,再重新定位最大值 TODO
                  printf("Finded max-pointer.\r\n"); //
                  LED0_SetLow();
                  fb_flag=0;
                  plan_step=0;
                }

            } else {
                printf("adc=%d, max=%d, step_all=%d\r\n", avr_result, adc_max, step_all); //
                // 转一圈,找最大值
                plan_step=STEPS_1DU;
            }
      }
    }
}定时器1中断处理代码如下:// 定时器1中断,1ms一次
void TMR1_DefaultInterruptHandler(void){
    uint8_t next_step=0;
    // add your TMR1 interrupt custom code
    // or set custom function using TMR1_SetInterruptHandler()
    // 交替LED作为指示
    //LATFbits.LATF3 = ~LATFbits.LATF3;
    if (fb_flag>0 && plan_step>0) {
      // 允许转动,并且预定了步进步数的场合,启动转动
      // 每间隔固定时间让步进马达走一步
       timer1_int_cnt++;
       if (timer1_int_cnt==step_period_ms) {
         timer1_int_cnt=0;
         if (fb_flag==1) {
               // 正转场合,取得本次步进数据的数据索引
               stepmotor_pos=(stepmotor_pos+1)%STEP_MAX;
         } else if (fb_flag==2) {
               // 反转场合,取得本次步进数据的数据索引
               stepmotor_pos=(stepmotor_pos+STEP_MAX-1)%STEP_MAX;
         }
         // 取得本次步进用时序数据
         next_step=F_Rotation;
         // 执行一次步进
         LATF = (LATF & 0x0F) | next_step;
         // 预定步进总数减一
         plan_step--;
         // 总步数加1
         step_all++;
       }      
    } else {
      timer1_int_cnt=0;
      LATF = LATF & 0x0F;
    }
}测试时按照两种模式:1、连接电脑测试,通过串口监测中间处理数据,检查程序逻辑。2、离线测试①在1的测试OK的情况下,把整个装置放置在正常光线下测试。②在正常光线下,在与正常光强最强角度不同的某一个角度上利用强光LED手电筒,设置为最强角度,测试装置是否能停留在这个角度。经过这三种简单的测试,证明了程序可以使装置转到最佳光强位置。实际应用中,可以利用这种思路动态调整太阳能在充电装置,保证在任意时刻找到最合理的角度完成太阳能到电能的转换。

robertesth 发表于 2022-8-17 16:00

有读取温湿度的程序吗   

zerorobert 发表于 2022-8-18 17:44

光照传感器了解一下。   

kkzz 发表于 2022-9-5 13:10

这个高端了。   

xiaoyaozt 发表于 2022-9-5 14:09

如何调整角度?   

zerorobert 发表于 2022-9-5 15:09

能够实现跟随吗?   

pzsh 发表于 2022-11-8 15:38

类似于机器学习?
页: [1]
查看完整版本: 【CuriosityNano测评报告】光强角度检测装置