Страница 1 из 1

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

Добавлено: Вт сен 08, 2015 10:25:42
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.

В общем хэлп, бьюсь об стену.

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

Добавлено: Вт сен 08, 2015 19:50:58
mr_smit
Прошу прощения за истерический вопль. У меня просто не правильно считалась контрольная сумма посылки. crc = 0 находилось в начале функции на AVR и я по запарке забыл её скопировать в CooCox.

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

crc = 0;  // ДОБАВИТЬ
for (i=0;i<8;i++) {
  crc = crc + buffer[i];                 // считаем контрольную сумму
}
Стыд и срам :oops: . Удалите тему.

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

Добавлено: Вт сен 08, 2015 20:38:43
Mishany
не надо удалять начинающим на стм пригодиться. я в их числе...

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

Добавлено: Вт сен 08, 2015 20:43:26
dosikus
mr_smit писал(а): Стыд и срам :oops: . Удалите тему.
Ну допустим не только это...

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

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

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

 USART_ClearITPendingBit(USART1, USART_IT_RXNE);

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

Добавлено: Пт сен 18, 2015 05:47:01
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 я сбрасываю когда обрабатываю прерывание по приему байта.

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

Добавлено: Пт сен 18, 2015 13:15:54
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.

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

Добавлено: Пт сен 18, 2015 18:55:53
mr_smit
Хм... Ну может быть