Как-то понадобилось изучить протокол — DMX-512 И научится правильно «принимать» посылки. В интернете, о протоколе DMX — информации достаточно DMX Простите за низкое качество фото.
DMX-512 целиком произошел от стандарта RS-485.
Основное отличие DMX от RS-485 это то, что в DMX есть «Break». В RS-485 это воспринимается как ошибка передачи данных. В DMX скорость передачи данных строго определена и составляет 250 кб. в сек. Передача данных осуществляется восьми битным асинхронным протоколом с одним стартовым битом (низкий активный уровень) и двумя стоповыми битами. Один фрейм = 11 бит. Длина пакета 44 микросекунды. Передаваемая информация находится между стартовым и стповыми битами и имеет 256 уникальных состояний от 0 до 255. Появление низкого уровня после всего пакета (512 фреймов) данных воспринимается как начало нового пакета. Количество каналов = фреймов, считываемых прибором с линии ДМХ зависит от количества функций, заложеных производителем в прибор. Например одноканальный диммер (в смысле на одну нагрузку) отъедает от линии DMX только один (канал = фрейм). При изменении цифр от 0 до 255 в ДМХ пульте управления, процессор диммера считывает эту информацию и плавно изменяет выходное напряжение на нагрузке от 0 вольт до 220 вольт. Линия ДМХ позволяет управлять пятьсот двенадцатью одноканальными приборами.
Если в приборе указать стартовый адрес ДМХ отличный от 1, например 24, то прибор считывает число только с 24 фрейма. На остальных каналах (фреймах) могут находится другие приборы. Главное сообщить прибору с какого фрейма он начинает принимать информацию.
Результат работы в массиве DMX_array[512]; (Keil, Debugger).
DMX тестер посылает «20» в первом канале.
#include "stm32f10x.h" #include "core_cm3.h" void USART3_init(void); void _delay_ms (int long); void USART3_TX_data (unsigned char); uint8_t USART2_RX_data(void); void TIM2_enabled(uint8_t, long int arr, long int psc); void Printf(char *data); void EXTI3_enabled(uint8_t on); uint8_t USART3_RX_data(void); uint8_t timer_full; uint8_t start_bit; uint8_t DMX_array[512]; unsigned char temp; int long reset; long int i; int main(void) { RCC -> APB2ENR |= RCC_APB2ENR_IOPBEN; RCC -> APB1ENR |= RCC_APB1ENR_USART2EN; RCC -> APB1ENR |= RCC_APB1ENR_USART3EN; RCC -> APB2ENR |= RCC_APB2ENR_IOPAEN; RCC -> APB2ENR |= RCC_APB2ENR_IOPDEN; RCC-> APB2ENR |= RCC_APB2ENR_AFIOEN; RCC-> APB1ENR |= RCC_APB1ENR_TIM2EN; GPIOB->CRH|=GPIO_CRH_MODE10; GPIOB->CRH |= GPIO_CRH_CNF10; GPIOB->CRH &=~ GPIO_CRH_CNF10_0; // PORTB 10 - out GPIOB->CRH &=~ GPIO_CRH_MODE11; GPIOB->CRH |= GPIO_CRH_CNF11; GPIOB->CRH &=~ GPIO_CRH_CNF11_0; // PORTA 3 - input [[:wiki:dmx_512|DMX]] GPIOD->CRH |= GPIO_CRH_MODE11; GPIOD->CRH &=~ GPIO_CRH_CNF11; // PORTD 9 - out USART_debuger GPIOB->CRH &=~ GPIO_CRH_MODE9; GPIOB->CRH |= GPIO_CRH_CNF9; GPIOB->CRH &=~ GPIO_CRH_CNF9_0; RCC -> CFGR = RCC_CFGR_SW_1; // PLL-on USART3_init(); while (1) { // Основной цикл if(!(GPIOB->IDR & GPIO_IDR_IDR11)) // Начало, start_bit, timer_full =0 { if(start_bit==0) { EXTI3_enabled(1); // Включить внешнее прерывание на DMX_input TIM2_enabled(1, 80, 100); // На 115 Мкс start_bit=1; } } // Выходим, крутимся пока не сработает таймер. // Пока он считает до 115 Мкс - внешних прерываний быть не должно. // Если будут - reset++, и будет больше 0, значит это не стартовый бит if(timer_full==1) // первое прерывания срабатывает сразу после включения внешнего прерывания { if(reset<=1) // Не больше 1 { while(!(GPIOB->IDR & GPIO_IDR_IDR11)){}; // Подождем когда закончится низкий уровень стартового бита, // сюда надо добавить сторожа на зацикливание!! EXTI3_enabled(0); // Внешние прерывания выключить // Определение MAB timer_full=0; TIM2_enabled(1, 5, 100); // На 9,500 Мкс reset=0; EXTI3_enabled(1); // Внешние прерывания включить while(timer_full==0){}; // Ждем прерывания таймера через 9,500 Мкс if(reset==0) // Перепадов быть не должно { temp = USART3_RX_data(); TIM2_enabled(0, 0, 0); // Выключить reset=0; EXTI3_enabled(0); // Выключить // Первый бит start_bit = USART3_RX_data(); if(start_bit==0){ // Должен быть 0 // Старт DMX распознан правильно, попадаем к данным // Цикл чтения 512 байтов for(i=0;i<512;i++) { DMX_array[i]= USART3_RX_data(); } i=0; // Все обнулить timer_full=0; start_bit=0; TIM2_enabled(0,0,0); reset=0; }} // Не стартовый бит, ошибка timer_full=0; start_bit=0; reset=0; TIM2_enabled(0,0,0); } } } } } void EXTI3_enabled(uint8_t on) { if(on==1){ AFIO->EXTICR [0] |= AFIO_EXTICR1_EXTI3_PA; // Прерывание на PIND 3 NVIC_EnableIRQ (EXTI3_IRQn);// Разрешить прерывание EXTI->IMR |= EXTI_IMR_MR3; // Прерывание EXTI->RTSR |= EXTI_IMR_MR3; // Спаду EXTI->FTSR |= EXTI_IMR_MR3; // Подьему } else { AFIO->EXTICR [0] &=~ AFIO_EXTICR1_EXTI3_PA; // Прерывание на PIND 3 NVIC_EnableIRQ (EXTI3_IRQn); // Разрешить прерывание EXTI->IMR &=~ EXTI_IMR_MR3; EXTI->EMR &=~ EXTI_IMR_MR3; EXTI->RTSR &=~ EXTI_IMR_MR3; EXTI->FTSR &=~ EXTI_IMR_MR3; } } void EXTI3_IRQHandler (void) { if (EXTI->PR & (1<<3)) { EXTI->PR |= (1<<3); // Сбросить флаг EXTI3 reset++; // Если по выходу переменная будет > 0, значит это не стартовый бит } } void TIM2_IRQHandler (void) // TIM2 INTERRUPT { TIM2->SR &= ~TIM_SR_UIF; timer_full++; start_bit=0; TIM2_enabled(0,0,0); } void TIM2_enabled(uint8_t condition, long int arr, long int psc){ if(condition==1) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; NVIC_EnableIRQ(TIM2_IRQn); TIM2->ARR = arr; TIM2->PSC = psc; TIM2->CR1 |= TIM_CR1_CEN; TIM2->DIER |= TIM_DIER_UIE; TIM2->CNT = 0x00; } if(condition==0) { RCC->APB1ENR &=~ RCC_APB1ENR_TIM2EN; NVIC_DisableIRQ(TIM2_IRQn); TIM2->ARR = arr; TIM2->PSC = psc; TIM2->CR1 &=~ TIM_CR1_CEN; TIM2->DIER &=~ TIM_DIER_UIE; TIM2->CNT = 0x00; } } void USART3_init(void){ USART3->CR1 |= (USART_CR1_TE)|(USART_CR1_RE); USART3->BRR= 0x00000120; // 250000 kb/s (72 000 000 + 250 000 / 2) / 250 000 USART3->CR1 |=USART_CR1_UE; USART3->CR2 |= USART_CR2_STOP_1; } void USART3_TX_data(uint8_t data){ while (!(USART3->SR & USART_SR_TXE)) {} USART3->DR=data; while (!(USART3->SR & USART_SR_TXE)) {} USART3->SR &=~ USART_SR_TXE; } void Printf(char *data){ while(*data) { while (!(USART3->SR & USART_SR_TXE)) {} USART3->DR= *data++; while (!(USART3->SR & USART_SR_TXE)) {} } } uint8_t USART3_RX_data(void){ uint8_t a; while (!(USART3->SR & USART_SR_RXNE)){ }; a = USART3->DR; return a; } void _delay_ms (int long delay){ int long a; for (a=0; a<delay; a++){}}
Отлаживалось на демоплате STM_Eval-Board-STM32 (STM32F103VB)
Спасибо за статью khomin
Купить STM32F103 на Aliexpress ~ 350-500руб.