[PIC®/AVR®/dsPIC®产品] 【CuriosityNano测评报告】光强角度检测装置

[复制链接]
 楼主| suncat0504 发表于 2022-7-27 18:47 | 显示全部楼层 |阅读模式
<
本帖最后由 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中的最大值对比,数值接近的就视为光强最大的检测角度,停止转动。
主程序代码如下:
  1. // 步进电机正反转标志
  2. extern uint8_t fb_flag;
  3. // 预定步进数
  4. extern uint16_t plan_step;
  5. // 总步数(用来定位最强的位置)
  6. volatile uint16_t step_all=0;
  7. // ADC最大值
  8. uint16_t adc_max=0;

  9. /*
  10.                          Main application
  11. */
  12. void main(void) {
  13.     // ADC转换用高、低8位数据
  14.     uint8_t resultHigh=0;
  15.     uint8_t resultLow=0;
  16.     uint16_t result=0;
  17.     double avrs[ADC_AVR_CNT];
  18.     uint8_t idx=0;
  19.     uint16_t avr_result=0;       // 本次采集平均值

  20.     // Initialize the device
  21.     SYSTEM_Initialize();

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

  29.     // Enable the Global Interrupts
  30.     INTERRUPT_GlobalInterruptEnable();

  31.     int i;
  32.    
  33.     // LED指示
  34.     LED0_SetLow();
  35.    
  36. // 初始化动作,表明程序运转
  37.     fb_flag=1;
  38.     plan_step=512;
  39.     __delay_ms(1000);
  40.     fb_flag=2;
  41. plan_step=512;

  42. // LED指示
  43.     LED0_SetHigh();
  44.     __delay_ms(2000);

  45.     fb_flag=0;

  46.     // 启动转动,同时收集ADC数据
  47.     step_all=0;
  48.     fb_flag=1;   // 正转方式
  49.     idx=0;
  50.    
  51.     // 主循环处理
  52.     while (1) {
  53.         // 触发ADC转换,并取得转换结果
  54.         ADCON0bits.GO = 1; //Start conversion
  55.         while (ADCON0bits.GO); //Wait for conversion done
  56.         resultHigh = ADRESH; //Read result
  57.         resultLow = ADRESL; //Read result
  58.         // 合成为16位数据
  59.         result=resultHigh;
  60.         result=result*256 + resultLow;
  61.         
  62.         // 计算平均值,并存储
  63.         avrs[idx]=result/ADC_AVR_CNT;
  64.         idx=(idx+1)%ADC_AVR_CNT;
  65.         if (idx==0) {
  66.             // 数据初始化
  67.             avr_result=0;
  68.             
  69.             // 满指定组数据了,求出平均结果
  70.             for (i = 0; i < ADC_AVR_CNT; i++) {
  71.                avr_result=avr_result+avrs[i];
  72.             }
  73.             if (avr_result > adc_max && step_all < STEPS_CYCLE) {
  74.                 adc_max = avr_result;
  75.             }         
  76.             

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

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

  91.             } else {
  92.                 printf("adc=%d, max=%d, step_all=%d\r\n", avr_result, adc_max, step_all); //
  93.                 // 转一圈,找最大值
  94.                 plan_step=STEPS_1DU;
  95.             }
  96.         }
  97.     }
  98. }
定时器1中断处理代码如下:
  1. // 定时器1中断,1ms一次
  2. void TMR1_DefaultInterruptHandler(void){
  3.     uint8_t next_step=0;
  4.     // add your TMR1 interrupt custom code
  5.     // or set custom function using TMR1_SetInterruptHandler()
  6.     // 交替LED作为指示
  7.     //LATFbits.LATF3 = ~LATFbits.LATF3;
  8.     if (fb_flag>0 && plan_step>0) {
  9.         // 允许转动,并且预定了步进步数的场合,启动转动
  10.         // 每间隔固定时间让步进马达走一步
  11.        timer1_int_cnt++;
  12.        if (timer1_int_cnt==step_period_ms) {
  13.            timer1_int_cnt=0;
  14.            if (fb_flag==1) {
  15.                // 正转场合,取得本次步进数据的数据索引
  16.                stepmotor_pos=(stepmotor_pos+1)%STEP_MAX;
  17.            } else if (fb_flag==2) {
  18.                // 反转场合,取得本次步进数据的数据索引
  19.                stepmotor_pos=(stepmotor_pos+STEP_MAX-1)%STEP_MAX;
  20.            }
  21.            // 取得本次步进用时序数据
  22.            next_step=F_Rotation[stepmotor_pos];
  23.            // 执行一次步进
  24.            LATF = (LATF & 0x0F) | next_step;
  25.            // 预定步进总数减一
  26.            plan_step--;
  27.            // 总步数加1
  28.            step_all++;
  29.        }      
  30.     } else {
  31.         timer1_int_cnt=0;
  32.         LATF = LATF & 0x0F;
  33.     }
  34. }
测试时按照两种模式:
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 | 显示全部楼层
类似于机器学习?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

158

主题

4504

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部