基于华芯微特SWM181CBT6单片机的DMX512的接收开发
某舞台灯光资深工程师说我推广的华芯微特的32位单片机SWM181CBT6不支持DMX512的协议,我偏偏不信这个邪,只好找出板子重操旧业调试起来。发现只用FIFO的阈值中断与线路空闲中断就搞定了。源代码: 9G-SWM181X-dmx-20210429.rar (4.18 MB)
代码:
#include "main.h"
#define DMX_BUFF_MAX 520
__align(4) uint8_t dmx_buf[DMX_BUFF_MAX];
uint32_t dmx_length=0;
uint8_t dmx_active=0;
__align(4) uint8_t uart_buf[DMX_BUFF_MAX];
uint32_t dmx_index=0;
uint32_t dmx_getbuf(uint8_t *buf){while(!dmx_active){;} memcpy(buf,dmx_buf,dmx_length);dmx_active=0;return dmx_length;}
void DMXInit(void)
{
UART_InitStructure UART_initStruct;
PORT_Init(PORTA, PIN0, FUNMUX_UART0_RXD, 1); //GPIOA.0配置为UART0输入引脚
PORT_Init(PORTA, PIN1, FUNMUX_UART0_TXD, 0); //GPIOA.1配置为UART0输出引脚
UART_initStruct.Baudrate = 250000;
UART_initStruct.DataBits = UART_DATA_9BIT; //数据位位数,可取值UART_DATA_8BIT、UART_DATA_9BIT
UART_initStruct.Parity = UART_PARITY_NONE; //奇偶校验位,可取值UART_PARITY_NONE、UART_PARITY_ODD、UART_PARITY_EVEN、UART_PARITY_ONE、UART_PARITY_ZERO
UART_initStruct.StopBits = UART_STOP_1BIT; //停止位位数,可取值UART_STOP_1BIT、UART_STOP_2BIT
UART_initStruct.TXThreshold = 0; //取值0--7
UART_initStruct.TXThresholdIEn = 0; //当TX FIFO中数据个数 <= TXThreshold时触发中断
UART_initStruct.RXThreshold = 7; //取值0--7
UART_initStruct.RXThresholdIEn = 1; //当RX FIFO中数据个数 >= RXThreshold时触发中断
UART_initStruct.TimeoutTime = 2; //超时时长 = TimeoutTime/(Baudrate/10) 秒 = 2/25000 = 80uS
UART_initStruct.TimeoutIEn = 1; //超时中断,超过 TimeoutTime/(Baudrate/10) 秒没有在RX线上接收到数据时触发中断
UART_Init(UART0, &UART_initStruct);
UART_Open(UART0);
IRQ_Connect(IRQ16_31_UART0, IRQ18_IRQ, 0);
}
void IRQ18_Handler(void)
{
uint32_t tmp;
if(UART_INTRXThresholdStat(UART0))//阈值中断
{
for(uint16_t i=0;i<6;i++) //读取6个字节,留1个给超时中断再读,否则缓冲空了产生不了超时中断
{
if(UART_ReadByte(UART0, &tmp) == 0)
{
if(dmx_index>=DMX_BUFF_MAX){dmx_index=0;} //防止缓冲溢出重新把接收指针指向缓冲开始
if(tmp<0x100){dmx_index=0;} //收到StartCode把接收指针指向缓冲开始
uart_buf[dmx_index++] = tmp&0xff; //读取字符
}
else{dmx_index=0;} //字符出错丢弃后重新把接收指针指向缓冲开始
}
}else
if(UART_INTTimeoutStat(UART0)) //超时中断
{
while(UART_IsRXFIFOEmpty(UART0) == 0)
{
if(UART_ReadByte(UART0, &tmp) == 0)
{
if(dmx_index>=DMX_BUFF_MAX){dmx_index=0;} //防止缓冲溢出重新把接收指针指向缓冲开始
if(tmp<0x100){dmx_index=0;} //收到StartCode把接收指针指向缓冲开始
uart_buf[dmx_index++] = tmp&0xff; //读取字符
}
else{dmx_index=0;} //字符出错丢弃后重新把接收指针指向缓冲开始
}
memcpy(dmx_buf, uart_buf, dmx_index); //超时了,就是数据包结束了,取走全部数据
dmx_length=dmx_index;dmx_index=0;dmx_active=1; //取走接收数据长度并重新把接收指针指向缓冲开始,表明数据有效
printf("L=%d\n\r",dmx_length);
for(int i=0;i<11;i++){printf("%d ",dmx_buf);}
}
else
{
//printf("EEE%x\n\r",UART0->CTRL);
}
}