Страница 1 из 2
LPC1768 + RS485
Добавлено: Вт апр 23, 2013 11:25:07
greenrat
Приветствую разработчиков)
я новичок в программировании ARM, раньше все больше на Atmega программировал
начал разбираться с UART, брал стандартные примеры от Keil, но возникли непонятные проблемы. Сразу оговорюсь - на выходе с Уартов стоят изолированные RS485 - на каждый уарт свой изолированный ADM485.
Весь фокус в том что с одного на другой уарт с RS485-ми все нормально отсылается и принимается. А если послать пакет например на UART0 и ответить на этот же UART с контроллера - информация приходит искаженной, словно где то режется байт или не переключается какой то регистр...
вот пример как я отправляю пакет в шину RS485 (UART0)
Код: Выделить всё
void RS485_Send_Polling(uint32_t portNum, uint8_t *BufferPtr, uint32_t Length)
{
uint32_t i;
if (portNum==0)
{
//Переключаем на передачу
LPC_GPIO2->FIOSET = 1UL<<8
for ( i = 0; i < Length; i++ ) {
// Ждем освобождения места в буфере передачи
while ( !((LPC_UART0->LSR>>LSR_THRE_BIT) & 1) );
LPC_UART0->THR = *BufferPtr++;
}
while ( !((LPC_UART0->LSR>>LSR_TEMT_BIT) & 1) );
//Переключаем на прием
LPC_GPIO2->FIOCLR = 1UL<<8
}
...
}
нет ли у кого примеров правильной работы LPC1768 c RS485? (в инете искал - но там все больше идет обсуждение нерабочих UART а про RS485 практически ничего нет или есть но советуют UART1)
Я знаю что есть UART1 и он завязан на RS485, но для задачи необходимо использование все 4-е уарта.
Re: LPC1768 + RS485
Добавлено: Ср апр 24, 2013 07:21:21
korsaj
485 - это физический уровень, т.е. неважно какой юарт вы используете. Как вариант контроллер не успевает передать байт до того как вы его переключаете на прием. Вначале проверте завершение передачи, а уж потом переводите на прием.
Re: LPC1768 + RS485
Добавлено: Ср апр 24, 2013 07:26:15
korsaj
Пользуюсь примерами от сюда
http://code.google.com/p/32bitmicro/sou ... leSoftwareЯ с компом через ЮАРТ общался без проблем, - прием байта от компа, изменение его и отправка обратно (типо эхосигнала).
А еще мне непонятно назначение этих строк
Код: Выделить всё
while ( !((LPC_UART0->LSR>>LSR_THRE_BIT) & 1) );
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 07:56:26
greenrat
while ( !((LPC_UART0->LSR>>LSR_THRE_BIT) & 1) );
это проверка регистра на то что байт был отослан
в принципе сейчас вроде все работает, но иногда выскакивают странные глюки
то нормально обмен идет то при следующем включении обработается одна команда и все -
виснет в выше указанном цикле
возможно это как то связано с аппаратными буферами а именно передатчика - по умолчанию он настроен на 16 байт
попробую его поменять на 1 байт - если разберусь как

,
потом отпишусь о результате
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 08:18:03
korsaj
Не проверка, а зацикливание, пока условие не ложно.
Спрошу по другому - Обясните как у вас работает данное условие while ( !((LPC_UART0->LSR>>LSR_THRE_BIT) & 1) );
чему равна константа LSR_THRE_BIT и есть ли смысл тратить процессорное время на сдвиг..
Не проще ли было для процессора, написать так while ( !(LPC_UART0->LSR & LSR_THRE_BIT) ); где LSR_THRE_BIT = 0х0020
Или так while (((LPC_UART0->LSR & LSR_THRE_BIT) != LSR_THRE_BIT ); где LSR_THRE_BIT = 0х0020
Еще вопрос какой литературой пользуетесь для освоения данного мк?
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 11:20:58
greenrat
хорошо - приведу пример как у меня сейчас
Код: Выделить всё
#define rs485C0_init set(LPC_GPIO2->FIODIR,1UL<<8)
#define rs485C0_RX LPC_GPIO2->FIOCLR = 1UL<<8
#define rs485C0_TX LPC_GPIO2->FIOSET = 1UL<<8
volatile uint32_t UART0_rx_rd_index;
volatile uint32_t UART0_rx_counter;
volatile uint8_t UART0_TxEmpty = 1;
volatile uint32_t UART0_Status=0;
volatile uint8_t UART0_rx_Buffer[UART0_BufferSize];
ПрерываниеКод: Выделить всё
void UART0_IRQHandler (void)
{
uint8_t IIRValue, LSRValue;
uint8_t Dummy = Dummy;
IIRValue = LPC_UART0->IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = LPC_UART0->LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
UART0_Status = LSRValue;
Dummy = LPC_UART0->RBR;
return;
}
else
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
UART0_rx_Buffer[UART0_rx_counter] = LPC_UART0->RBR;
UART0_rx_counter++;
if (UART0_rx_counter == UART0_BufferSize)
{
UART0_rx_counter=0;
}
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
UART0_rx_Buffer[UART0_rx_counter] = LPC_UART0->RBR;
UART0_rx_counter++;
if (UART0_rx_counter == UART0_BufferSize)
{
UART0_rx_counter=0;
}
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
UART0_Status |= 0x100; /* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = LPC_UART0->LSR; /* Check status in the LSR to see if
valid data in U0THR or not */
if ( LSRValue & LSR_THRE )
{
UART0_TxEmpty = 1;
}
else
{
UART0_TxEmpty = 0;
}
}
}
ИнициализацияКод: Выделить всё
uint8_t UART_Init( uint8_t PortNum, uint32_t baudrate )
{
uint32_t pclkdiv;
uint32_t pclk;
uint32_t fdiv;
uint32_t regVal;
NVIC_DisableIRQ(UART0_IRQn);
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART0, ENABLE);
LPC_PINCON->PINSEL0 |= (1 << 4); // Pin P0.2 used as TXD0
LPC_PINCON->PINSEL0 |= (1 << 6); // Pin P0.3 used as RXD0
//Peripheral clock selection for UART0 - PCLKSEL0.7:6
pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
switch (pclkdiv) {
case 0x00:
default:
pclk = SystemCoreClock/4; break;
case 0x01: pclk = SystemCoreClock; break;
case 0x02: pclk = SystemCoreClock/2; break;
case 0x03: pclk = SystemCoreClock/8; break;
}
LPC_UART0->LCR = 0x83; //8 bits, no Parity, 1 Stop bit, enable access to Divisor Latches
fdiv = (pclk / 16) / baudrate; //baud rate
LPC_UART0->DLM = fdiv / 256;
LPC_UART0->DLL = fdiv % 256;
clr(LPC_UART0->LCR,(1<<7)); //Disable access to Divisor Latches
//FIFO Control Register. Controls UART FIFO usage and modes.
LPC_UART0->FCR = 0x07; //Enable and reset TX and RX FIFO (16 and 16 byte)
// Читаем регистр статуса линии для его очистки
regVal = LPC_UART0->LSR;
// Что бы удостовериться в отсутствии мусора ждем очистки буфера передачи
while (LPC_UART0->LSR & (LSR_THRE | LSR_TEMT) != (LSR_THRE | LSR_TEMT));
while (LPC_UART0->LSR & LSR_RDR) {
regVal = LPC_UART0->RBR; // и пока они есть считываем «в никуда» данные из буфера приёма
}
//Enable interrupt
NVIC_EnableIRQ(UART0_IRQn);
LPC_UART0->IER = IER_RBR | IER_RLS | IER_THRE;
}
Отправка байтаКод: Выделить всё
void RS485x_Send_Polling(uint8_t portNum, uint8_t *BufferPtr, uint32_t Length)
{
uint32_t i;
LPC_UART0->IER = IER_THRE | IER_RLS; //Disable RBR
rs485C0_TX;
for ( i = 0; i < Length; i++ ) {
while ( !(UART0_TxEmpty & 0x01) );
LPC_UART0->THR = *BufferPtr++;
UART0_TxEmpty = 0;
}
while ( !(UART0_TxEmpty & 0x01) );
rs485C0_RX;
LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR; // Re-enable RBR
return;
}
дальше просто в цикле смотрю есть что либо в буфере и если что есть - обрабатываю
если не вникая в код я тут использовал стандартный пример от Keil для работы с UART добавил только
переключение ножки RS485 (rs485C0_RX; rs485C0_TX;)
при обработке - смотрю есть ли у меня во входном буфере данные - если есть то их обрабатываю
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 12:48:45
korsaj
Пример стандартный. Только строкой while ( !((LPC_UART0->LSR>>LSR_THRE_BIT) & 1) ); вы "подвешиваете" цикл. Мк будет крутится на этой строке пока буфер не пуст. Лучще сделать проверку в основном цикле этого бита и если он не установлен продолжать выполнения программы.
А еще лучще сделать это в прерывании, тем более в примере все есть в обработчике прерываний. И по идеи вы должны в цикле проверять
UART0_TxEmptyСмотрите в побработчике последнюю инструкцию
else ifВот она:
Код: Выделить всё
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = LPC_UART0->LSR; /* Check status in the LSR to see if
valid data in U0THR or not */
if ( LSRValue & LSR_THRE )
{
UART0_TxEmpty = 1;
}
else
{
UART0_TxEmpty = 0;
}
}
Собственно в функции RS485x_Send_Polling уже все реализовано.
Вот в этой книге можно немного почерпнуть о работе мк
Микроконтроллеры ARM7 семейств LPC 2300/2400. Вводный курс разработчикаА вот эту книгу я нигде не найду
http://dodeca.ru/books/228/
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 13:26:58
greenrat
Спасибо) я тоже уже подумал перенести отслеживание передачи пакета в прерывание и завершать - переключать ногу - там же
книжку поищу - если найду скину сюда ссылку
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 13:54:37
ibiza11
korsaj писал(а):Вот в этой книге можно немного почерпнуть о работе мк Микроконтроллеры ARM7 семейств LPC 2300/2400. Вводный курс разработчика

Вы хоть сами эту книжку читали? Если бы прочли, то такого бы не заявляли:
korsaj писал(а):и есть ли смысл тратить процессорное время на сдвиг..?
PS Книжка годная, советую! Несмотря на то, что LPC1768 - Cortex-M3, а в книжке про ARM7. Очень полезное чтиво для перехода от 8-битного "мышления".
Не мудрено, её еще не напечатали даже) Пока можете почитать это: "Joseph Yiu. The Definitive Guide to the ARM Cortex-M3."
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 14:34:18
korsaj
ibiza11 писал(а): 
Вы хоть сами эту книжку читали? Если бы прочли, то такого бы не заявляли:
korsaj писал(а):и есть ли смысл тратить процессорное время на сдвиг..?
А собственно разве гуманно в цикле с проверкой условия каждый раз выполнять LPC_UART0->LSR>>LSR_THRE_BIT - что собственно значит сдвиг в право значения поля LSR структуры LPC_UART0 на LSR_THRE_BIT (32) бита?
Книгу читал, даю слово )
Может правда не все усвоил.
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 14:50:53
ibiza11
вот одна из команд, которая поддерживается Cortex-M3
AND{S}.W <Rd>,<Rn>,<Rm>{,<shift>} Bitwise AND register value with shifted register value
Будете Вы сдвигать значение регистра перед операцией побитового И(bitwise AND) со значением 0x01 или не будете, ядру все равно, команда одна. Компилятор хоть так, хоть эдак этот код преобразует в одну команду.
на LSR_THRE_BIT (32) бита?
LSR_THRE_BIT = 32? или что Вы имеете в виду? LSR - фактически это Line Status Register, а THRE - Transmitter Holding Register Empty - флаг опустошения регистра передачи UART (5ый бит 32-битного регистра LSR).
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:03:49
korsaj
С одной командой согласен..
Вот по тому мой вопрос выше в постах звучал, чему равен LSR_THRE_BIT?
LSR_THRE_BIT = 0000 0000 0010 0000 вот так выглядит в бинарке, вот так в кексе 0х0020 ну а вот так в дес. 32.
LSR_THRE_BIT = 5.
Исправляю последнююю строку чтоб бы меня понимали
или LSR_THRE_BIT = 5
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:23:47
ibiza11
А откуда Вы взяли значение этой константы? Я так понимаю, что эта константа (LSR_THRE_BIT) объявлена в стандартной библиотеке от NXP?
я стараюсь не пользоваться ей. В стандартном файле описания периферии более продвинутого семейства (LPC177x_8x.h) я такого объявления не нашел.
Зато нашел другое объявление
Код: Выделить всё
#define UART_LSR_THRE ((uint8_t)(1<<5)) /*!<Line status register: Transmit holding register empty*/
korsaj писал(а):Книгу читал, даю слово )
Может правда не все усвоил.
Ну да, как то избирательно прочли) Глава 1. Раздел 1.6.2. Команды обработки данных (стр.22 моего издания) (Это у меня настольная книга, если что)
korsaj писал(а):LSR_THRE_BIT = 0000 0000 0010 0000 вот так выглядит в бинарке, вот так в кексе 0х0020 ну а вот так в дес. 32.
LSR_THRE_BIT = 5.
Вот этого совсем не понял. Как это одновременно и 32 и 5 ?

Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:34:53
korsaj
Тю на вас..
Там же не написано что одновременно, я продположил что константа равна 32, а ниже написал второй вариант что она равна 5
)))
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:45:25
ibiza11

Ну Вы и хамло. Ваши предположения из головы необходимо в текст сообщения выносить, чтобы Вас понимали.
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:46:24
korsaj
ibiza11 писал(а):Ну да, как то избирательно прочли) Глава 1. Раздел 1.6.2. Команды обработки данных (стр.22 моего издания) (Это у меня настольная книга, если что)
Точно изберательно читал (успел только 1 раз прочесть, неделю с этим мк воюю), совершенно этого не помню. А может не понял сразу и потому незапомнилось. Вот у вас настольная, а я купить все не могу, хотя хочу. Конечно больше хочу купить ту которую еще не начали печатать, но к сожеелнию додека морозится, я им писал, и книга у них в анонсе уже давно вроде с 2011 года.
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 15:47:01
korsaj
ibiza11 
Ну Вы и хамло. Ваши предположения из головы необходимо в текст сообщения выносить, чтобы Вас понимали.
Пальцы чешутся? Так купите себе наждачку, а не об клаву их чешите.
Вот теперь я хамло, как и Вы.
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 18:08:08
ibiza11
я Вам не хамил.
Возвращаясь к теме, прошу автора пояснить чему же все таки равна эта злосчастная константа.
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 20:12:56
greenrat
У меня она равна
#define LSR_THRE_BIT 5
попробовал сегодня перенести все в прерывание - в принципе работает - теперь без бесконечного цикла, но все равно иногда какой то косяк выскакивает - шлет пакет - получает ответ
следующая команда почему то не проходит. раз несколько вызываю эту команду и через раз или пару раз - набор команд проходит как надо. Причем замечено - что если просто слать какому то девайсу
набор пакетов без ответа - все работает четко, как только вклинивается ответ то все идет на перекосяк... Странный вообщем глюк - на атмегах у меня такого не было.
Буду разбираться дальше - толи прерывание не срабатывает толи еще что...
Re: LPC1768 + RS485
Добавлено: Пт апр 26, 2013 20:41:44
korsaj
Покажите обработчик прерывания. Возможно вы переключаете направление до того как UART успел передать/принять байт.