打印
[PIC®/AVR®/dsPIC®产品]

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

[复制链接]
819|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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[ADC_AVR_CNT];
    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[idx]=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[i];
            }
            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[stepmotor_pos];
           // 执行一次步进
           LATF = (LATF & 0x0F) | next_step;
           // 预定步进总数减一
           plan_step--;
           // 总步数加1
           step_all++;
       }      
    } else {
        timer1_int_cnt=0;
        LATF = LATF & 0x0F;
    }
}
测试时按照两种模式:
1、连接电脑测试,通过串口监测中间处理数据,检查程序逻辑。
2、离线测试
①在1的测试OK的情况下,把整个装置放置在正常光线下测试。
②在正常光线下,在与正常光强最强角度不同的某一个角度上利用强光LED手电筒,设置为最强角度,测试装置是否能停留在这个角度。
  经过这三种简单的测试,证明了程序可以使装置转到最佳光强位置。实际应用中,可以利用这种思路动态调整太阳能在充电装置,保证在任意时刻找到最合理的角度完成太阳能到电能的转换。
project.zip (1007.48 KB)

使用特权

评论回复
沙发
robertesth| | 2022-8-17 16:00 | 只看该作者
有读取温湿度的程序吗   

使用特权

评论回复
板凳
zerorobert| | 2022-8-18 17:44 | 只看该作者
光照传感器了解一下。   

使用特权

评论回复
地板
kkzz| | 2022-9-5 13:10 | 只看该作者
这个高端了。   

使用特权

评论回复
5
xiaoyaozt| | 2022-9-5 14:09 | 只看该作者
如何调整角度?   

使用特权

评论回复
6
zerorobert| | 2022-9-5 15:09 | 只看该作者
能够实现跟随吗?     

使用特权

评论回复
7
pzsh| | 2022-11-8 15:38 | 只看该作者
类似于机器学习?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:大连伊飞特信息技术有限公司软件工程师
简介:本人于1993年毕业于大连理工大学。毕业后从事单片机开发工作5年,之后转入软件开发工作至今。

130

主题

3968

帖子

5

粉丝