Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » Архив » STM32 UART


STM32 UART

Сообщений 1 страница 30 из 70

1

На примере F4 дискавери .
Для других линеек будет далее.

2

Код:
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);}
	
}

3

Ну, это самый простой способ передачи - без прерываний, пусть он будет первый. Его можно использовать, если есть какая-то RTOS, которая будет непрерывно передавать байты в какой-либо задаче. А без RTOS передать на скорости 9600 256 байт - это почти 256 миллисекунд ожидания.

Есть еще два варианта работы с UART, которые я обычно и использую:
второй - с использованием прерываний;
третий - с ипользованием контроллера DMA (на мой взгляд самый оптимальный).

Я, конечно, предположу, что цель у автора топика показать простой пример, а не подарить всем желающим оптимальный код. А то с чего тогда жить будем, если всё раздадим. :)

4

Извольте, с прерываниями. 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++;
	  }
}

5

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;
    
	}
}

6

dosikus написал(а):

Извольте, с прерываниями. F0 , Переделать, по образу и подобию на F4, сможет и начинающий.

Пускай тот начинающий, который захочет адаптировать код от F072 на F407 сам и переносит код, пускай трудятся,  т.к. у меня код совсем другой для STM32F407, там и модули DMA отличаются и регистры другие.  :) Ты особо не спеши портироать код для популярного (F407), а то заберут себе на сайт и затем выдадут за свое.

Логика открывания кода (преподования...ну, или какая у тебя цель...может, признание сообщества...) должна быть такая (IMHO): слон поел - покакал, прилетели птички и стали клевать полупереваренное, но им доступное. Т.е. птички не должны есть вместо слона еду слона. :) Т.е. птички и слон могут существовать в симбиозе и всем от этого польза. Закон жизни. Но в нашем случае птички еще могут сообщать об обнаруженных ошибках в коде, тогда совсем смысл есть.

PS: Я не к тому написал про еще методы, что ты как бы не умеешь, а просто не понял смысла простого примера.

Отредактировано Pridnya (2017-03-28 10:05:47)

7

Дим ,пусть будет пока как есть, будет время и распишу работу и подотру...

8

dosikus написал(а):

Дим ,пусть будет пока как есть, будет время и распишу работу и подотру...

А зачем ты пытаешься выложить самый совершенный (на пределе своих возможностей) код все всем? Вообще не понимаю.
Код должен работать. Если хочешь показать свой код, то нужно показывать тем, кто этот код потребляет и реализует в готовых изделиях,
тогда есть смысл, может, чего перепадет за работу, но, вообще-то должно так быть: есть рабочий код - есть доход. А у тебя какой смысл?
Может, ты сомневаешься в совершенстве кода и хочешь довести его до совершенства с помощью сообщества? Но сообщество не такое щедрое как ты и я,
даром свое время тратить не будет.

9

Я вот не согласен.
dosikus дает код. у тех кто читает два варианта, просто скопировать код или вникнуть в код. Первый вариант не интересен , потому что для тупого копирования есть Куб и Хал - нагенерил и пользуешься. 

Поэтому лично мне интересно читать и анализировать, т.е. учиться "как надо". А если не выкладывать код,то можно только тему с флудом оставить.

10

Atomic-dm, да пусть ищет скрытый смысл в моих действиях. :)
Дим, я пишу о том что мне интересно, интересно поделиться с другими. Возможно я и пишу в пустоту...

11

Я на Диму вообще бы не реагировал... Мало ли кто в нём сей сейчас поселился... больной... или доктор... В условно белых халатах они у него одинаковы...

12

Стас, ты хоть не пропадай.
А то от скуки начинаю умалишенных  тыкать иглой...

13

dosikus написал(а):

Atomic-dm, да пусть ищет скрытый смысл в моих действиях. 
Дим, я пишу о том что мне интересно, интересно поделиться с другими. Возможно я и пишу в пустоту...

Я тож читаю и знаю откуда уже начинать для примера.
Только может сделать отдельную ветку для учебы молодым в этом деле,а не писать в этой теме обсуждая надо это или нет.
К тому из-за уроков dosikus и потянутся сюда люди.

Отредактировано CERGEI (2017-03-29 06:45:18)

14

dosikus написал(а):

тыкать иглой...

Кстати, а не устаканить ли нам тут официально обращение на ты в Правилах ?
my504 после этого тут, наверно, не появится, но может это и к лучшему )

CERGEI написал(а):

Только может сделать отдельную ветку для учебы молодым в этом деле,а не писать в этой теме обсуждая надо это или нет.

CERGEI, так заводи ветку )
Вообще, структура форума не окончательная - как только будет, если будет,  появляться материал, будем добавлять разделы.
Ясно, что пока не хватает, как минимум, adc/dac, usb (тут я и сам обещаюсь), rtos ...

Насчёт выкладывания кода, я тоже бы начал выкладывать, но пользую headers с битовыми полями, и будет кто в лес, кто по дрова.
Пока раздумываю как лучше приспособиться - то ли спец доп header с битовыми полями делать и прикладывать, то ли к макросам вернуться

Отредактировано vt340 (2017-03-29 11:22:10)

15

vt340 написал(а):

Кстати, а не устаканить ли нам тут официально обращение на ты в Правилах ?
my504 после этого тут, наверно, не появится, но может это и к лучшему )

Давно пора, а то есть дети по 20 лет, которые хотят, чтобы к ним дяди в два раза старше их на вы обращались.
Ну, или пень какой, к которому на вы ну никак не охота обращаться.

16

Мой вариант 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 );
}

17

linuxbergi
Странный способ принимать данные, попахивает Ардуино. Ну хотя бы на прерываниях + таймер на тайм аут, или ДМА + IDLE.

18

linuxbergi написал(а):

Мой вариант USART, аскетичный в духе vt340

Нет, не в моём духе, любая блокирующая операция моему духу антагонистична )

19

Ну, send можно иногда и блокирующий сделать, но receive блокирующий — это уж совсем...
Но у STM32 есть уйма веселых вещей: DMA, прерывания и т.п. Можно заполнять буфер через DMA и включить прерывание при обнаружении символа конца строки — как только строку получили, имеем автоматом выставленный флаг, и можно запустить обработчик буфера. А уж передавать через DMA — так вообще милое дело! Разве что при больших потоках данных или малых скоростях нужно 2-3 буфера заводить, иначе опять придется блокировать...

20

Eddy_Em
Не подскажешь как это сделать (прерывание при обнаружении символа конца строки), что-то я такое не припоминаю.

21

MasterElectric это есть в F0 .

22

Ага, я здесь так и делал, но потом меня обложили матюками, и я стал использовать посимвольный обработчик с таймаутом.

23

Неправильное понимание назначение примеров программирования железа. Прежде всего - это сосредоточение на конфигурировании железа, а не на программистких вывертах. Когда человек знакомится с HW, всё ново и незнакомо и до конца не ясно, где главное, а где второстепенное. А про прерывания слышал и у меня есть примеры с обработчиками и на передачу и на приём.

24

dosikus написал(а):

USART1->BRR =(APB2CLK+BAUDRATE/2)/BAUDRATE;

а что это за странная формула, как ее вывели почему не USART1->BRR = APB2CLK / BAUDRATE;

25

MasterElectric написал(а):

а что это за странная формула, как ее вывели почему не USART1->BRR = APB2CLK / BAUDRATE;

я кстати ее тоже проверял когда увидел... но она верна :)

26

А что вас удивило??? Обычное математическое округление...

27

Всем привет) Решил переписать свою библиотеку modbus master и использовать dma. Все хорошо, но прием происходит сдвинутый на 1 байт.
http://s8.uploads.ru/t/p0ZnW.png
Вместо нулевого байта должен быть первый, вместо первого второй и тд.
И раньше встречался с такой проблемой, но обходил ее увеличением  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);
}

28

что то я не нашел место где эта структура заполняется

29

Atomic-dm написал(а):

что то я не нашел место где эта структура заполняется

Извиняюсь, забыл.

Код:

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");
	    }
	}
    }
}


30

Вот ссылка на проект Ссылка


Вы здесь » Микроконтроллеры » Архив » STM32 UART