使用某些主频比较低的芯片时比如航顺的HK32F030M系列的芯片时,该芯片的主频使用最高32M的内部RC振荡器,没有PLL,没有DMA,对于WS2812这类对时钟频率要求比较高的IC有些困难。虽然使用一些技巧也是可以驱动的,比如直接使用寄存器操作,减少不必要的开销等。
为了将驱动负担降低到底,我尝试使用汇编的方式驱动WS2812,并且取得成功,在MCU工作在32M的状况下,成功将刷新时钟上到800k。
下面介绍一下具体方法。在正常工程中,添加一个新文件(Add New Item),文件类型选择asm (*.s)
;//驱动WS2812的引脚 ,高速翻转达到200ns,
;/*传入参数:
;1.引脚的地址
;2.一个灯的32位数据
;*/
;LED0 EQU 0x48000C18 PD4
AREA DriveWS2812,CODE ,READONLY
EXPORT F_DriveWS2812;导出函数
F_DriveWS2812
PUSH {R0,R1,R2,R3,R4,R5,R6,R7, LR};R2,,R3,R4,R5,R6,R7
MOVS R7,R1;LSL#8;将参数2的值先向左移8位到数据的24bit高位位置
MOVS R4,#0x01
LSLS R4,R4,#23;0x800000
MOVS R3,#0;R3用于24位计数
MOVS R5,R0;
ADDS R5,#0x10;BSx地址改变到BRx地址, 用于复位
MOVS R6,#0x10;操作寄存器用的值输出Gpio_Pin_4
LOOP
ADDS R3,R3,#1
CMP R3,#24
BHI LOOP_END
ANDS R7,R7,R4;和0x800000做与后比较
CMP R7,#0
BLS DAT0;大于
STR R6,[R0];输出1
LSLS R1,R1,#1
MOVS R7,R1
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
STR R6,[R5] ;输出0
B LOOP
DAT0
STR R6,[R0];输出1
LSLS R1,R1,#1
MOVS R7,R1
STR R6,[R5] ;输出0
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
B LOOP
LOOP_END
POP {R0,R1,R2,R3,R4,R5,R6,R7,PC};,R2,R3,R4,R5,R6,R7
END
调用方法
{
uint32_t j;
GPIO_INIT();
j=0;
for(i=0;i<32;i++){//驱动灯珠的数量32
F_DriveWS2812(LEDPIN,j);//汇编函数调用
}
j++;//颜色
Delay(500);//帧间隔
}