- 严重flicker
- 中等flicker
- 轻微flicker
从实际的测试可以看出来,随着flicker程度的变化,DC值并没有明显的变化,而AC值会越来越小。
最简单的方法,采集一堆数据,然后求最大值,最小值,平均值,最后代入上面的公式即可。但是这样抗干扰的能力太弱,电信号必然有高频噪声在。因此需要做一些简单的滤波。
这里采用的简单算法如下:
- 采集N个周期的数据
- 升序排序
- 去掉最大值,最小值
- 取前面N-1个数的平均值作为最小值
- 取后面N-1个数的平均值作为最大值
- 求平均值
- 代入上面的公式
很明显,需要使用ADC采样。flicker的周期约为50ms。按照10倍采样率,采样周期5ms。采集N个周期,采集的数据量将会是10*N。因此设计如下:
- ADC 设置成Timer触发测量,DMA模式
- Timer 设置周期5ms的PWM
- DMA总长10*N,开DMA完成中断
- 中断产生后,切换buffer,并发出信号量,开始算法
注意算法需要在50*N ms内完成。
硅光电池对不同的亮度转换不同的电压值,经过放大器之后,输出的电压值可能会饱和或者太低。需要自适应调节反馈电阻。
从实际测量的波形,可以看到DC值其实比较稳定,且很好计算。因此可以利用DC值做自适应的算法。比如说,将DC值控制在1V到2V之间。
测量周期 50*N ms,因此测量频率大于等于20HZ。
- UART通讯,波特率115200,双工,无奇偶校验,1个起始位,1个停止位
- 每两个数据包之间至少要有1ms的间隔时间
用C表示为
__packed typedef struct
{
uint8_t DeviceID;
uint8_t PackageID;
uint16_t DataLength;
uint8_t *Data;
uint8_t Crc8;
}PackageTypeDef;
- DeviceID : 设备ID号,表明是什么设备,目前分配如下:
typedef enum
{
TP = 0,
FLCIKER_SENSOR,
U_DISK
}DeviceIDTypeDef;
- PackageID : 表示这个包是干啥用的,自定义
- DataLength : 数据区长度
- Data : 数据
- Crc8 : 对前面所有数据进行Crc计算得出的数据,计算方式如下:
/**
* Static table used for the table_driven implementation.
*****************************************************************************/
static const crc8_t crc_table[256] = { 0x00, 0x4d, 0x9a, 0xd7, 0x79, 0x34, 0xe3,
0xae, 0xf2, 0xbf, 0x68, 0x25, 0x8b, 0xc6, 0x11, 0x5c, 0xa9, 0xe4, 0x33,
0x7e, 0xd0, 0x9d, 0x4a, 0x07, 0x5b, 0x16, 0xc1, 0x8c, 0x22, 0x6f, 0xb8,
0xf5, 0x1f, 0x52, 0x85, 0xc8, 0x66, 0x2b, 0xfc, 0xb1, 0xed, 0xa0, 0x77,
0x3a, 0x94, 0xd9, 0x0e, 0x43, 0xb6, 0xfb, 0x2c, 0x61, 0xcf, 0x82, 0x55,
0x18, 0x44, 0x09, 0xde, 0x93, 0x3d, 0x70, 0xa7, 0xea, 0x3e, 0x73, 0xa4,
0xe9, 0x47, 0x0a, 0xdd, 0x90, 0xcc, 0x81, 0x56, 0x1b, 0xb5, 0xf8, 0x2f,
0x62, 0x97, 0xda, 0x0d, 0x40, 0xee, 0xa3, 0x74, 0x39, 0x65, 0x28, 0xff,
0xb2, 0x1c, 0x51, 0x86, 0xcb, 0x21, 0x6c, 0xbb, 0xf6, 0x58, 0x15, 0xc2,
0x8f, 0xd3, 0x9e, 0x49, 0x04, 0xaa, 0xe7, 0x30, 0x7d, 0x88, 0xc5, 0x12,
0x5f, 0xf1, 0xbc, 0x6b, 0x26, 0x7a, 0x37, 0xe0, 0xad, 0x03, 0x4e, 0x99,
0xd4, 0x7c, 0x31, 0xe6, 0xab, 0x05, 0x48, 0x9f, 0xd2, 0x8e, 0xc3, 0x14,
0x59, 0xf7, 0xba, 0x6d, 0x20, 0xd5, 0x98, 0x4f, 0x02, 0xac, 0xe1, 0x36,
0x7b, 0x27, 0x6a, 0xbd, 0xf0, 0x5e, 0x13, 0xc4, 0x89, 0x63, 0x2e, 0xf9,
0xb4, 0x1a, 0x57, 0x80, 0xcd, 0x91, 0xdc, 0x0b, 0x46, 0xe8, 0xa5, 0x72,
0x3f, 0xca, 0x87, 0x50, 0x1d, 0xb3, 0xfe, 0x29, 0x64, 0x38, 0x75, 0xa2,
0xef, 0x41, 0x0c, 0xdb, 0x96, 0x42, 0x0f, 0xd8, 0x95, 0x3b, 0x76, 0xa1,
0xec, 0xb0, 0xfd, 0x2a, 0x67, 0xc9, 0x84, 0x53, 0x1e, 0xeb, 0xa6, 0x71,
0x3c, 0x92, 0xdf, 0x08, 0x45, 0x19, 0x54, 0x83, 0xce, 0x60, 0x2d, 0xfa,
0xb7, 0x5d, 0x10, 0xc7, 0x8a, 0x24, 0x69, 0xbe, 0xf3, 0xaf, 0xe2, 0x35,
0x78, 0xd6, 0x9b, 0x4c, 0x01, 0xf4, 0xb9, 0x6e, 0x23, 0x8d, 0xc0, 0x17,
0x5a, 0x06, 0x4b, 0x9c, 0xd1, 0x7f, 0x32, 0xe5, 0xa8 };
uint8_t CalCrc8(const uint8_t *data, uint16_t data_len)
{
uint8_t crc = 0xff;
while (data_len--)
{
crc = crc_table[(crc ^ *data) & 0xff];
data++;
}
return crc;
}
假设TP要发送一个结果数据过来,参考代码如下:
typedef enum
{
NG = 0,
PASS = 1,
}ResultTypeDef;
typedef enum
{
RESULT,
}IDTypeDef;
void SendResult(ResultTypeDef result)
{
PackageTypeDef package;
package.DeviceID = TP;
package.PackageID = RESULT;
package.DataLength = sizeof(ResultTypeDef);
package.Data = (uint8_t *)&result;
package.Crc8 = CalCrc8(...);
UART_Send(...);
...
}