На примере F4 дискавери .
Для других линеек будет далее.
STM32 UART
Сообщений 1 страница 30 из 70
Поделиться12017-02-14 14:34:29
Поделиться22017-02-18 14:20:15
void Usart1_Init (void) { RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->AHB1ENR |=RCC_AHB1ENR_GPIOBEN; GPIOB->AFR[0] |= (7<<28)|(7<<24); // AF7 for PB6 & PB7 GPIOB->MODER &=~ GPIO_MODER_MODER6 | GPIO_MODER_MODER7 ; GPIOB->MODER|= GPIO_MODER_MODER6_1| GPIO_MODER_MODER7_1 ; GPIOB->OSPEEDR|= GPIO_OSPEEDER_OSPEEDR6| GPIO_OSPEEDER_OSPEEDR7 ; USART1->BRR =(APB2CLK+BAUDRATE/2)/BAUDRATE; USART1->CR1 = USART_CR1_TE | USART_CR1_RE| USART_CR1_RXNEIE; USART1->CR1 |= USART_CR1_UE; } void Usart1_send(char data) { while (!(USART1->SR & USART_SR_TXE)) {}; USART1->DR = data; } void USART1_str (const char * data) { char c; while((c=*data ++)){ Usart1_send(c);} }
Поделиться32017-03-28 08:32:28
Ну, это самый простой способ передачи - без прерываний, пусть он будет первый. Его можно использовать, если есть какая-то RTOS, которая будет непрерывно передавать байты в какой-либо задаче. А без RTOS передать на скорости 9600 256 байт - это почти 256 миллисекунд ожидания.
Есть еще два варианта работы с UART, которые я обычно и использую:
второй - с использованием прерываний;
третий - с ипользованием контроллера DMA (на мой взгляд самый оптимальный).
Я, конечно, предположу, что цель у автора топика показать простой пример, а не подарить всем желающим оптимальный код. А то с чего тогда жить будем, если всё раздадим.
Поделиться42017-03-28 08:51:50
Извольте, с прерываниями. F0 , Переделать, по образу и подобию на F4, сможет и начинающий.
#define APBCLK 48000000UL #define BAUDRATE 115200UL
void Usart_init (void) { RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB2ENR|=RCC_APB2ENR_USART1EN; GPIOA->MODER &= ~( GPIO_MODER_MODER10 |GPIO_MODER_MODER9); GPIOA->MODER |= GPIO_MODER_MODER10_1 |GPIO_MODER_MODER9_1; GPIOA->AFR[1] |=(1<<(4*1)) |(1<<(4*2)); USART1->BRR =(APBCLK+BAUDRATE/2)/BAUDRATE; USART1->CR1 |= USART_CR1_TE |USART_CR1_RE|USART_CR1_RXNEIE; USART1->CR1 |= USART_CR1_UE; NVIC_SetPriority(USART1_IRQn, 0); NVIC_EnableIRQ(USART1_IRQn); } void Usart_Transmit(uint8_t Data) { while(!(USART1->ISR & USART_ISR_TC)); USART1->TDR = Data; } void USART1_IRQHandler(void) { uint8_t rx; if(USART1->ISR & USART_ISR_RXNE) { rx = (USART1->RDR); // Receive data, clear flag } } void USART1_str (const char * data) { while((*data )){ Usart_Transmit (*data); data++; } }
Поделиться52017-03-28 09:05:37
F072 , modbus RTU, DMA,
#define APBCLK 48000000UL #define BAUDRATE 115200UL #define RX_BUF_SIZE 200
extern uint8_t RX_flag; volatile uint8_t RX_bufer[RX_BUF_SIZE]={0}; void Usart_init (void) { RCC->AHBENR |= RCC_AHBENR_GPIOAEN|RCC_AHBENR_DMAEN; RCC->APB2ENR|=RCC_APB2ENR_USART1EN; DMA1_Channel3->CPAR = (uint32_t)(&(USART1->RDR)); // DMA channel x peripheral address register DMA1_Channel3->CMAR = (uint32_t)RX_bufer; // DMA channel x memory address register DMA1_Channel3->CNDTR = (uint32_t)RX_BUF_SIZE; // DMA channel x number of data register DMA1_Channel3->CCR |= DMA_CCR_PL; // Channel Priority level Very High DMA1_Channel3->CCR |= DMA_CCR_MINC; // Memory increment mode GPIOA->MODER &= ~( GPIO_MODER_MODER10 |GPIO_MODER_MODER9); GPIOA->MODER |= GPIO_MODER_MODER10_1 |GPIO_MODER_MODER9_1; GPIOA->PUPDR |=GPIO_PUPDR_PUPDR9_0 |GPIO_PUPDR_PUPDR10_0; GPIOA->AFR[1] |=(1<<(4*1)) |(1<<(4*2)); USART1->BRR =(APBCLK+BAUDRATE/2)/BAUDRATE; //usart USART1->CR2|=USART_CR2_RTOEN; USART1->RTOR= 30; USART1->CR3|=USART_CR3_DMAR; USART1->CR1 |= USART_CR1_TE |USART_CR1_RE|USART_CR1_RTOIE; USART1->CR1 |= USART_CR1_UE; NVIC_SetPriority(USART1_IRQn, 0); NVIC_EnableIRQ(USART1_IRQn); DMA1_Channel3 ->CCR |= DMA_CCR_EN; } void Usart_Transmit(uint8_t Data) { while(!(USART1->ISR & USART_ISR_TC)); USART1->TDR = Data; } void USART1_IRQHandler(void) { uint16_t rx; if(USART1->ISR & USART_ISR_RTOF) { DMA1_Channel3 ->CCR &= ~DMA_CCR_EN; USART1->ICR|=USART_ICR_RTOCF; RX_flag=1; } } void USART1_str (const char * data) { while((*data )){ Usart_Transmit (*data); data++; } }
uint8_t RX_flag=0; extern uint8_t RX_bufer[]; while(1) { if(RX_flag) { uint8_t index,count; count =RX_BUF_SIZE-(DMA1_Channel3->CNDTR); RX_flag =0; for(index=0;index<9;index++) { Usart_Transmit(MODBUS_bufer[index]); } while(!(USART1->ISR & USART_ISR_TC)); DMA1_Channel3->CNDTR=RX_BUF_SIZE; DMA1_Channel3 ->CCR |= DMA_CCR_EN; } }
Поделиться62017-03-28 10:01:22
Извольте, с прерываниями. F0 , Переделать, по образу и подобию на F4, сможет и начинающий.
Пускай тот начинающий, который захочет адаптировать код от F072 на F407 сам и переносит код, пускай трудятся, т.к. у меня код совсем другой для STM32F407, там и модули DMA отличаются и регистры другие. Ты особо не спеши портироать код для популярного (F407), а то заберут себе на сайт и затем выдадут за свое.
Логика открывания кода (преподования...ну, или какая у тебя цель...может, признание сообщества...) должна быть такая (IMHO): слон поел - покакал, прилетели птички и стали клевать полупереваренное, но им доступное. Т.е. птички не должны есть вместо слона еду слона. Т.е. птички и слон могут существовать в симбиозе и всем от этого польза. Закон жизни. Но в нашем случае птички еще могут сообщать об обнаруженных ошибках в коде, тогда совсем смысл есть.
PS: Я не к тому написал про еще методы, что ты как бы не умеешь, а просто не понял смысла простого примера.
Отредактировано Pridnya (2017-03-28 10:05:47)
Поделиться72017-03-28 10:26:59
Дим ,пусть будет пока как есть, будет время и распишу работу и подотру...
Поделиться82017-03-28 10:38:56
Дим ,пусть будет пока как есть, будет время и распишу работу и подотру...
А зачем ты пытаешься выложить самый совершенный (на пределе своих возможностей) код все всем? Вообще не понимаю.
Код должен работать. Если хочешь показать свой код, то нужно показывать тем, кто этот код потребляет и реализует в готовых изделиях,
тогда есть смысл, может, чего перепадет за работу, но, вообще-то должно так быть: есть рабочий код - есть доход. А у тебя какой смысл?
Может, ты сомневаешься в совершенстве кода и хочешь довести его до совершенства с помощью сообщества? Но сообщество не такое щедрое как ты и я,
даром свое время тратить не будет.
Поделиться92017-03-28 19:08:05
Я вот не согласен.
dosikus дает код. у тех кто читает два варианта, просто скопировать код или вникнуть в код. Первый вариант не интересен , потому что для тупого копирования есть Куб и Хал - нагенерил и пользуешься.
Поэтому лично мне интересно читать и анализировать, т.е. учиться "как надо". А если не выкладывать код,то можно только тему с флудом оставить.
Поделиться102017-03-28 20:45:42
Atomic-dm, да пусть ищет скрытый смысл в моих действиях.
Дим, я пишу о том что мне интересно, интересно поделиться с другими. Возможно я и пишу в пустоту...
Поделиться112017-03-28 21:12:59
Я на Диму вообще бы не реагировал... Мало ли кто в нём сей сейчас поселился... больной... или доктор... В условно белых халатах они у него одинаковы...
Поделиться122017-03-28 21:30:22
Стас, ты хоть не пропадай.
А то от скуки начинаю умалишенных тыкать иглой...
Поделиться132017-03-29 06:44:26
Atomic-dm, да пусть ищет скрытый смысл в моих действиях.
Дим, я пишу о том что мне интересно, интересно поделиться с другими. Возможно я и пишу в пустоту...
Я тож читаю и знаю откуда уже начинать для примера.
Только может сделать отдельную ветку для учебы молодым в этом деле,а не писать в этой теме обсуждая надо это или нет.
К тому из-за уроков dosikus и потянутся сюда люди.
Отредактировано CERGEI (2017-03-29 06:45:18)
Поделиться142017-03-29 09:32:53
тыкать иглой...
Кстати, а не устаканить ли нам тут официально обращение на ты в Правилах ?
my504 после этого тут, наверно, не появится, но может это и к лучшему )
Только может сделать отдельную ветку для учебы молодым в этом деле,а не писать в этой теме обсуждая надо это или нет.
CERGEI, так заводи ветку )
Вообще, структура форума не окончательная - как только будет, если будет, появляться материал, будем добавлять разделы.
Ясно, что пока не хватает, как минимум, adc/dac, usb (тут я и сам обещаюсь), rtos ...
Насчёт выкладывания кода, я тоже бы начал выкладывать, но пользую headers с битовыми полями, и будет кто в лес, кто по дрова.
Пока раздумываю как лучше приспособиться - то ли спец доп header с битовыми полями делать и прикладывать, то ли к макросам вернуться
Отредактировано vt340 (2017-03-29 11:22:10)
Поделиться152017-03-29 14:07:45
Кстати, а не устаканить ли нам тут официально обращение на ты в Правилах ?
my504 после этого тут, наверно, не появится, но может это и к лучшему )
Давно пора, а то есть дети по 20 лет, которые хотят, чтобы к ним дяди в два раза старше их на вы обращались.
Ну, или пень какой, к которому на вы ну никак не охота обращаться.
Поделиться162017-07-04 19:00:49
Мой вариант USART, аскетичный в духе vt340
void io_init(void)
{
/* Активируем GPIOA USART1 AFIO*/
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN;
//---------конф. GPIOA_9 на вывод AFIO Push-Pull USART 0b10100000----------
GPIOA -> CRH |= (uint32_t) 0x000000A0 ;
GPIOA -> CRH &= (uint32_t) 0xFFFFFFA0 ;
//-------------------------------------------------------------------------
USART1->BRR=0x09C4; // BaudRate 9600
// USART1 -> BRR=0xD0; //BaudRate 115200
USART1->CR1 |= USART_CR1_UE; // Разрешаем работу USART1
USART1->CR1 |= USART_CR1_TE; // Включаем передатчик
USART1->CR1 |= USART_CR1_RE; // Включаем приёмник
}
void putChar( uint8_t ch)
{
while(!(USART1 -> SR & USART_SR_TC)); //Ждем пока бит TC в регистре SR установится 1
USART1 -> DR = ch; //Отсылаем байт через UART
return;
}
uint8_t getChar(void)
{
while(!( USART1 -> SR & USART_SR_RXNE ) ) {}
return (USART1 -> DR );
}
Поделиться172017-07-04 23:59:18
linuxbergi
Странный способ принимать данные, попахивает Ардуино. Ну хотя бы на прерываниях + таймер на тайм аут, или ДМА + IDLE.
Поделиться182017-07-05 11:05:16
Мой вариант USART, аскетичный в духе vt340
Нет, не в моём духе, любая блокирующая операция моему духу антагонистична )
Поделиться192017-07-05 15:39:12
Ну, send можно иногда и блокирующий сделать, но receive блокирующий — это уж совсем...
Но у STM32 есть уйма веселых вещей: DMA, прерывания и т.п. Можно заполнять буфер через DMA и включить прерывание при обнаружении символа конца строки — как только строку получили, имеем автоматом выставленный флаг, и можно запустить обработчик буфера. А уж передавать через DMA — так вообще милое дело! Разве что при больших потоках данных или малых скоростях нужно 2-3 буфера заводить, иначе опять придется блокировать...
Поделиться202017-07-05 20:20:14
Eddy_Em
Не подскажешь как это сделать (прерывание при обнаружении символа конца строки), что-то я такое не припоминаю.
Поделиться212017-07-05 21:50:34
MasterElectric это есть в F0 .
Поделиться222017-07-05 22:39:00
Ага, я здесь так и делал, но потом меня обложили матюками, и я стал использовать посимвольный обработчик с таймаутом.
Поделиться232017-07-13 14:48:07
Неправильное понимание назначение примеров программирования железа. Прежде всего - это сосредоточение на конфигурировании железа, а не на программистких вывертах. Когда человек знакомится с HW, всё ново и незнакомо и до конца не ясно, где главное, а где второстепенное. А про прерывания слышал и у меня есть примеры с обработчиками и на передачу и на приём.
Поделиться242017-07-22 00:10:04
USART1->BRR =(APB2CLK+BAUDRATE/2)/BAUDRATE;
а что это за странная формула, как ее вывели почему не USART1->BRR = APB2CLK / BAUDRATE;
Поделиться252017-07-22 09:23:47
а что это за странная формула, как ее вывели почему не USART1->BRR = APB2CLK / BAUDRATE;
я кстати ее тоже проверял когда увидел... но она верна
Поделиться262017-07-23 12:20:41
А что вас удивило??? Обычное математическое округление...
Поделиться272017-08-21 09:34:53
Всем привет) Решил переписать свою библиотеку modbus master и использовать dma. Все хорошо, но прием происходит сдвинутый на 1 байт.
Вместо нулевого байта должен быть первый, вместо первого второй и тд.
И раньше встречался с такой проблемой, но обходил ее увеличением DMA1_Channel3 -> CNDTR на 1 и отбрасыванием 0 байта, но хотелось бы разобраться почему так и где косяк. Перечитываю референс, все вроде правильно. Чип STM32F103CB
Инициализация
void MODBUS_Master_Init(){ RCC -> APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; RCC -> APB1ENR |= RCC_APB1ENR_USART3EN | RCC_APB1ENR_TIM4EN; RCC -> AHBENR |= RCC_AHBENR_DMA1EN; stat.modbus_busy = 0; GPIOB -> CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE11); GPIOB -> CRH |= GPIO_CRH_CNF10_1 | GPIO_CRH_MODE10 | GPIO_CRH_CNF11_0; GPIOB -> CRL &= ~(GPIO_CRL_CNF2); GPIOB -> CRL |= GPIO_CRL_MODE2; DIR_LOW; TIM4 -> PSC = 7200 - 1; TIM4 -> ARR = 30000; //300ms TIM4 -> DIER = TIM_DIER_UIE; TIM4 -> CR1 = TIM_CR1_OPM; DMA1_Channel3 -> CPAR = (uint32_t)&USART3 -> DR; DMA1_Channel3 -> CCR = DMA_CCR1_PL_0 | DMA_CCR1_MINC | DMA_CCR1_TCIE; USART3 -> BRR = 3750; //9600 USART3 -> CR1 = USART_CR1_TCIE | USART_CR1_TE | USART_CR1_RE; USART3 -> CR2 = USART_CR2_STOP_1; USART3 -> CR3 = USART_CR3_DMAR; USART3 -> CR1 |= USART_CR1_UE; NVIC_EnableIRQ(USART3_IRQn); NVIC_EnableIRQ(DMA1_Channel3_IRQn); NVIC_EnableIRQ(TIM4_IRQn); }
Функция отправки
void MODBUS_Master_Send(_modbus_request modbus){ uint16_t crc; if (stat.modbus_busy) return; send_buf[0] = modbus.id; send_buf[1] = modbus.func; send_buf[2] = modbus.addr >> 8; send_buf[3] = modbus.addr; switch (modbus.func){ case 3: case 4: send_buf[4] = modbus.length_data >> 8; send_buf[5] = modbus.length_data; answer_len = 5 + modbus.length_data * 2; answ_buf = modbus.answer; send_counter = 8; break; } crc = crc_chk(send_buf, send_counter - 2); send_buf[send_counter - 2] = crc; send_buf[send_counter - 1] = crc >> 8; pointer = send_buf; stat.modbus_busy = 1; DIR_HIGH; //Оправляем send_buf USART3 -> CR1 |= USART_CR1_TXEIE; }
Обработчики прерываний
void USART3_IRQHandler(){ if (USART3 -> SR & USART_SR_TXE){ if (send_counter){ USART3 -> DR = *pointer++; send_counter--; } else { USART3 -> CR1 &= ~(USART_CR1_TXEIE); } } if (USART3 -> SR & USART_SR_TC){ USART3 -> SR = ~(USART_SR_TC); //Переводим PHY в режим приемника DIR_LOW; //Включаем таймер (таймаут) TIM4 -> CR1 |= TIM_CR1_CEN; //Настраиваем ДМА для приема пакета DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); DMA1_Channel3 -> CMAR = (uint32_t)answ_buf; DMA1_Channel3 -> CNDTR = answer_len; DMA1_Channel3 -> CCR |= DMA_CCR1_EN; } }
void DMA1_Channel3_IRQHandler(){ uint16_t crc; DMA1 -> IFCR |= DMA_IFCR_CTCIF3; TIM4 -> CNT = 0; TIM4 -> CR1 &= ~(TIM_CR1_CEN); DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); crc = crc_chk(answ_buf, answer_len - 2); if (crc == (answ_buf[answer_len - 2] | (answ_buf[answer_len - 1] << 8))){ stat.modbus_error = 0; } else { stat.modbus_error = 1; } stat.modbus_busy = 0; }
void TIM4_IRQHandler(){ TIM4 -> SR = ~(TIM_SR_UIF); stat.modbus_busy = 0; stat.modbus_error = 1; DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); }
Поделиться282017-08-21 11:05:26
что то я не нашел место где эта структура заполняется
Поделиться292017-08-21 11:11:34
что то я не нашел место где эта структура заполняется
Извиняюсь, забыл.
typedef struct { uint8_t id; uint8_t func; uint16_t addr; uint16_t length_data; uint8_t *write_data; uint8_t *answer; } _modbus_request; _modbus_request modbus uint8_t modbus_answer[100]; void main(void) { MODBUS_Master_Init(); SEGGER_RTT_Init(); modbus.id = 1; modbus.func = 3; modbus.addr = 0; modbus.length_data = 2; modbus.answer = modbus_answer; while(1){ MODBUS_Master_Send(modbus); modbus_stat = MODBUS_Master_GetStatus(); if (modbus_stat != 0xFF){ if (modbus_stat == 0){ LED1_ON; } else { LED1_OFF; SEGGER_RTT_WriteString(0, "RECEIVE ERROR\r\n"); } } } }
Поделиться302017-08-21 11:16:30
Вот ссылка на проект Ссылка