灯光板到了才发现AWTRIX时钟使用的灯光板和我画的灯板扫描顺序不太一样,固件需要修改。
我画的的扫描顺序:
原版的扫描顺序:
查阅 AWTRIX 的代码可以看到采用的是 FastLED_NeoMatrix 这个库,这个库是用 C++ 写的库,不过代码结构比较清晰,找出画点的函数 FastLED_NeoMatrix::drawPixel,函数实现如下
void FastLED_NeoMatrix::drawPixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
_leds[XY(x,y)] = passThruFlag ? passThruColor : expandColor(color);
}
其中 XY(x,y) 函数就是把屏幕的坐标点转换为_leds数组的索引,跳到XY(x,y)函数中查看。
int FastLED_NeoMatrix::XY(int16_t x, int16_t y) {
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return numpix-1;
int16_t t;
switch(rotation) {
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
int tileOffset = 0, pixelOffset;
if(remapFn) {
pixelOffset = (*remapFn)(x, y);
} else {
uint8_t corner = type & NEO_MATRIX_CORNER;
uint16_t minor, major, majorScale;
if(tilesX) {
uint16_t tile;
minor = x / matrixWidth;
major = y / matrixHeight,
x = x - (minor * matrixWidth);
y = y - (major * matrixHeight);
if(type & NEO_TILE_RIGHT) minor = tilesX - 1 - minor;
if(type & NEO_TILE_BOTTOM) major = tilesY - 1 - major;
if((type & NEO_TILE_AXIS) == NEO_TILE_ROWS) {
majorScale = tilesX;
} else {
_swap_uint16_t(major, minor);
majorScale = tilesY;
}
if((type & NEO_TILE_SEQUENCE) == NEO_TILE_PROGRESSIVE) {
tile = major * majorScale + minor;
} else {
if(major & 1) {
corner ^= NEO_MATRIX_CORNER;
tile = (major + 1) * majorScale - 1 - minor;
} else {
tile = major * majorScale + minor;
}
}
tileOffset = tile * matrixWidth * matrixHeight;
}
minor = x;
major = y;
if(corner & NEO_MATRIX_RIGHT) minor = matrixWidth - 1 - minor;
if(corner & NEO_MATRIX_BOTTOM) major = matrixHeight - 1 - major;
if((type & NEO_MATRIX_AXIS) == NEO_MATRIX_ROWS) {
majorScale = matrixWidth;
} else {
_swap_uint16_t(major, minor);
majorScale = matrixHeight;
}
if((type & NEO_MATRIX_SEQUENCE) == NEO_MATRIX_PROGRESSIVE) {
pixelOffset = major * majorScale + minor;
} else {
if(major & 1) pixelOffset = (major + 1) * majorScale - 1 - minor;
else pixelOffset = major * majorScale + minor;
}
}
return(tileOffset + pixelOffset);
}
这段代码就是根据当前的旋转方向等信息来计算偏移从而确定其索引。
其中有很重要的一行代码
if(remapFn) { // Custom X/Y remapping function
pixelOffset = (*remapFn)(x, y);
}
这行代码调用了一个回调函数,通过回调函数可以实现对于计算数组索引方法的自定义
我画的屏幕是横S形状的扫描方式,简单数学计算可以得到坐标和索引的变换关系为:
y 为偶数时 index = 32 * y;
y 为奇数时 index = 32 * y + 31 - x;
写一个转换函数
uint16_t remapDisp(uint16_t x, uint16_t y) {
if (y % 2) {
return (32 * y + x);
} else {
return (32 * y + (31 - x));
}
}
然后初始化函数 matrixInit 中添加一行注册代码,注册到XY函数的回调
matrix->setRemapFunction(remapDisp);
用 VSCode 中的 PIO 插件编译一下
烧录到ESP8266接上控制板,正常点亮。
PS:灯光板的大小超了这个木盒子,把四个角切掉,飞线解决;栅格板是用fashion360画,3D打印的,均光板直接剪的A4纸。