STM32F103VET6 передача массива байт по USART

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
mr_smit
Вымогатель припоя
Сообщения: 651
Зарегистрирован: Пн мар 23, 2009 09:25:58
Откуда: Самара

STM32F103VET6 передача массива байт по USART

Сообщение mr_smit »

Решил переделать одну железку с AVR на STM32. На USART что то конкретно запутался. Мозг кипит уже. В общем среда CooCox, камень STM32F103VET6 работает на 72 МГц. Железка отсылает по RS485 массив AB CD 01 FF 88. Компьютер обратно присылает ответ DC BA 01 00 72 00 FD 00 FA. Задача: разобрать ответ и выполнить действия. Казалось бы банально, но я туплю и не понимаю :(

На AVR я задаю массив:

Код: Выделить всё

unsigned char Zapros[] = {0xAB,0xCD,0x01,0xFF,0x88}; 
Включаю USART:
Спойлер

Код: Выделить всё

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 38400
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x17;
Разрешаю прерывание по приему байта и складываю принятые байты в буфер:
Спойлер

Код: Выделить всё

interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   buffer[counter] = data;
   if (++counter == BUFFER_SIZE) {
     counter = 0;
     }
   }
}
В основном цикле работаю с буфером и отправляю ответ:
Спойлер

Код: Выделить всё

void SendCommand (unsigned char *command, unsigned char length) {
  delay_ms(1);        // ждем перед отправкой
  DE = 1;             // выставляем на передачу
  while (length--) {
    while(!(UCSRA & (1<<UDRE)));  // ждем освобождения регистра UDR
    UDR = *command++;
  }
  delay_ms(1);       // ждем после отправки
  DE = 0;            // выставляем на прием
}

....

SendCommand(Zapros,5);
Интервал между запросами считает таймер. Всё работает как часы!

Теперь хочу то же самое проделать на STM32.

Массив:

Код: Выделить всё

uint8_t SendBuffer[] = {0xab,0xcd,0x01,0xff,0x88}; 
Для примера хочу помигать светодиодом в зависимости от принятой команды. Настраиваю пин для светодиода, пин для переключения приема/передачи и пины USART. Ещё запускаю таймер на отсчет 1 секунды.
Спойлер

Код: Выделить всё

GPIO_InitTypeDef LED;
   GPIO_InitTypeDef USART_PIN;
   USART_InitTypeDef USART_InitStruct;
   TIM_TimeBaseInitTypeDef TIM_InitStructure;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

   // PE14 -> LED PIN
   LED.GPIO_Pin = GPIO_Pin_14;
   LED.GPIO_Mode = GPIO_Mode_Out_PP;
   LED.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOE, &LED);
   GPIO_SetBits(GPIOE,GPIO_Pin_14);

   // PA9 -> TX USART
   USART_PIN.GPIO_Pin = GPIO_Pin_9;
   USART_PIN.GPIO_Mode = GPIO_Mode_AF_PP;
   USART_PIN.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOA, &USART_PIN);

   //PA10  -> RX USART
   USART_PIN.GPIO_Pin = GPIO_Pin_10;
   USART_PIN.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   USART_PIN.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOA, &USART_PIN);

   // PA11 -> DE (RS485)
   USART_PIN.GPIO_Pin = GPIO_Pin_11;
   USART_PIN.GPIO_Mode = GPIO_Mode_Out_PP;
   USART_PIN.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOA, &USART_PIN);

   USART_InitStruct.USART_BaudRate            = 38400;
   USART_InitStruct.USART_WordLength          = USART_WordLength_8b;
   USART_InitStruct.USART_StopBits            = USART_StopBits_1;
   USART_InitStruct.USART_Parity              = USART_Parity_No ;
   USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
   USART_InitStruct.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
   USART_Init (USART1, &USART_InitStruct);
   USART_Cmd(USART1, ENABLE);

   TIM_TimeBaseStructInit(&TIM_InitStructure);
   TIM_InitStructure.TIM_Prescaler = 7200-1;
   TIM_InitStructure.TIM_Period = 10000-1;
   TIM_InitStructure.TIM_ClockDivision = 0;
   TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseInit(TIM6, &TIM_InitStructure);
   TIM_Cmd(TIM6, ENABLE);

   NVIC_EnableIRQ(TIM6_IRQn);
   TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);

   NVIC_EnableIRQ(USART1_IRQn);
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // разрешаем прерывания RX
Обработка прерываний:
Спойлер

Код: Выделить всё

void TIM6_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
    USART_Enable_Send = 1;
  }
}

void USART1_IRQHandler(void)
{
  if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
      USART_ClearITPendingBit(USART1, USART_IT_RXNE);

      buffer[counter] = USART_ReceiveData(USART1);
      if (++counter == BUFFER_SIZE) {
	    counter = 0;
	  }
    }
}
Каждую секунду выставляем флаг USART_Enable_Send что пора передавать запрос.
Спойлер

Код: Выделить всё

 while(1)
	{
    	if (USART_Enable_Send == 1) {
    	  SendCommand (SendBuffer,5);
    	  USART_Enable_Send = 0;
    	}

    	if (counter > 8) {
    	  for (i=0;i<8;i++) {
    		crc = crc + buffer[i];                 // считаем контрольную сумму
    	  }
    	  i =  (~crc + 1) & 0xFF;                  // берем 2 младших разряда от двоичного дополнения
    	  if ( buffer[8] == i ) {

    		  if ((buffer[7] & (1<<0)) == 1) {  // если нулевой бит предпоследнего байта установлен (1)
    			  GPIOE->BSRR = GPIO_BSRR_BS14;  // зажечь светодиод
    		  }
    		  else {
    			  GPIOE->BSRR = GPIO_BSRR_BR14;
    		  }

    		  USART1->DR = buffer[7];
    	  }
    	  counter = 0;
    	}
}
1. Что нужно ещё добавить для стабильной работы USART? Может как то прерывания ещё настраивать надо?

2. Как правильно передать массив целиком? Как и самое главное где проверять окончание ПЕРЕДАЧИ? Перед отправкой следующего байта.

Код: Выделить всё

void delay_ms(uint32_t ms) {
	volatile uint32_t nCount;
	RCC_ClocksTypeDef RCC_Clocks;
	RCC_GetClocksFreq (&RCC_Clocks);
    nCount = (RCC_Clocks.HCLK_Frequency/10000)*ms;
    for (; nCount != 0; nCount--);
}

...

void SendCommand (uint8_t *command, uint8_t length) {
	counter = 0;
	GPIOA->BSRR = GPIO_BSRR_BS11; // выставляем DE на передачу

  while (length--) {
	while(!(USART1->SR & USART_SR_TC));  // ждем окончания передачи предыдущего байта
	USART1->DR = *command++;
  }
  delay_ms(1);       // ждем после отправки
  GPIOA->BSRR = GPIO_BSRR_BR11;   // выставляем DE на прием
}
Надо что то ещё добавлять или нет? Потому что светодиод у меня на плате не загорается. При старте обмена он загорается и постоянно горит. Снифил обмен. Передача вроде как идет. Но через секунд 10 программа на ПК падает по ошибке порта (на AVR не падает). Какая ошибка не понятно. У меня подозрение что я что то не донастроил на STM32.

В общем хэлп, бьюсь об стену.
Нельзя всё знать, достаточно понимать.
Реклама
Аватара пользователя
mr_smit
Вымогатель припоя
Сообщения: 651
Зарегистрирован: Пн мар 23, 2009 09:25:58
Откуда: Самара

Re: STM32F103VET6 передача массива байт по USART

Сообщение mr_smit »

Прошу прощения за истерический вопль. У меня просто не правильно считалась контрольная сумма посылки. crc = 0 находилось в начале функции на AVR и я по запарке забыл её скопировать в CooCox.

Код: Выделить всё

crc = 0;  // ДОБАВИТЬ
for (i=0;i<8;i++) {
  crc = crc + buffer[i];                 // считаем контрольную сумму
}
Стыд и срам :oops: . Удалите тему.
Нельзя всё знать, достаточно понимать.
Реклама
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: STM32F103VET6 передача массива байт по USART

Сообщение Mishany »

не надо удалять начинающим на стм пригодиться. я в их числе...
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: STM32F103VET6 передача массива байт по USART

Сообщение dosikus »

mr_smit писал(а): Стыд и срам :oops: . Удалите тему.
Ну допустим не только это...

Код: Выделить всё

 while(!(USART1->SR & USART_SR_TC)); 

Код: Выделить всё

 USART_ClearITPendingBit(USART1, USART_IT_RXNE);
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
mr_smit
Вымогатель припоя
Сообщения: 651
Зарегистрирован: Пн мар 23, 2009 09:25:58
Откуда: Самара

Re: STM32F103VET6 передача массива байт по USART

Сообщение mr_smit »

dosikus писал(а): Ну допустим не только это...

Код: Выделить всё

 while(!(USART1->SR & USART_SR_TC)); 

Код: Выделить всё

 USART_ClearITPendingBit(USART1, USART_IT_RXNE);
А причем здесь USART_IT_RXNE если меня в функции передачи интересует только передался байт или нет. Можно ли следующий отправлять USART_SR_TC (Transmission complete). USART_IT_RXNE я сбрасываю когда обрабатываю прерывание по приему байта.
Нельзя всё знать, достаточно понимать.
Реклама
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: STM32F103VET6 передача массива байт по USART

Сообщение dosikus »

Использовании SPL'ни не освобождает от чтения мануала.

На счет проверки TC
Bit 6 TC: Transmission complete
.....
This clearing
sequence is recommended only for multibuffer communication.
В то время как :
Bit 7 TXE: Transmit data register empty
.....
Note: This bit is used during single buffer transmission.
И о сбросе флага RXNE :
Bit 5 RXNE: Read data register not empty
.....
It is cleared by a read to the USART_DR register.
Реклама
Аватара пользователя
mr_smit
Вымогатель припоя
Сообщения: 651
Зарегистрирован: Пн мар 23, 2009 09:25:58
Откуда: Самара

Re: STM32F103VET6 передача массива байт по USART

Сообщение mr_smit »

Хм... Ну может быть
Нельзя всё знать, достаточно понимать.
Ответить

Вернуться в «ARM»