В общем думал я, что все будет по накатанной идти, а оказалось, что в использовании уарта в 18 серии есть некоторые различия.
Компилятор XC8 имеет набор встроенных функций для работы с периферией, найти заголовочные файлы можно в папке /includes/plib. Нас на данный момент интересует usart.h.
Сформулируем интересующие нас задачи:
- Запись одного символа
- Запись строки
- Чтение одного символа = 1 байта
- Чтение нескольких байт
Все это дело будем пробовать завести на PIC18F14K50.
Сначала я приведу картинки из протеуса, а уже файнал вершн будет в конце на реальной тестовой плате.
Поехали 🙂
Первым делом нужно как водится настроить уарт. Для этого существует функция OpenUSART(Config, baud), где Config это преднастройка по своему виду похожая на __CONFIG, а baud коэффициент, используемый при расчете бодрейта:
FOSC/[16 (baud+1)]
Попытаемся рассчитать этот коэффициент для бодрейта 9600 и кварца 12 МГц
baud = 12M/(9600*16) – 1 = 77.125 ~ 77
По поводу настроек конфига рекомендую обратиться в файлик pic18_plib.pdf, лежит в директории docs компилятора XC, там все очень подробно и прекрасно расписано.
Начнем с теста записи одного байта, для этого предназначена функция:
void WriteUSART(char data)
Ну вроде как все довольно прозрачно, пора практиковаться:
#include <xc.h> #include <plib/usart.h> #define _XTAL_FREQ 12000000 //The speed of your internal(or)external oscillator #pragma config WDTEN = OFF, LVP = OFF, FOSC = HS unsigned char UARTConfig = 0; baud = 0; char txbyte = 'U'; //наш байт для пересылки void main() { TRISB7 = 0; //TX pin set as output TRISB5 = 1; //RX pin set as input UARTConfig = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ; //прерывания выключены, асинхронный режим, 8 бит, высокоскоростной режим baud = 77; //Focs/(9600*16) - 1 OpenUSART(UARTConfig,baud); WriteUSART(txbyte); //Пишем наш байт while(1) { }//while(1) }//main
*Решил обновить подсветку синтаксиса, что-то меня старая начала угнетать 🙂
Тест:
Дальше надо бы строку научиться пулять 🙂
Для этих целей есть готовая функция:
void putsUSART( char *data)
Не знаю как у вас, а у меня сразу возник вопрос, можно ли с помощью этой функции передавать служебные символы, а так же как ей вывести полученные численные данные.
Ответ на первый вопрос – да, можно вводить любые служебные символы (типа \r\n) все отрабатывается замечательно, с числами сложнее, это не готовая функция printf.
Но не стоит расстраиваться, зато мы не тратим много памяти, и для чисел всегда можно написать готовую функцию для конвертации:
void NumToUart(unsigned int Num) //Число в уарт { unsigned int bignum = 10000; //максимальный делитель unsigned char numtemp = 5; //максимальное количество разрядов while(numtemp>0) //Определяем сколько разрядов имеет наше число { if (Num/bignum) break; numtemp--; bignum = bignum / 10; } for (unsigned char i = numtemp; i>0; i--) { WriteUSART( (Num - (Num/(bignum*10))*bignum*10 )/bignum + '0'); //Выталкиеваем все разряды - от старшего к младшему while(BusyUSART()); //Ждем пока освободится модуль иначе будут прострелы bignum = bignum/10; } }
Кстати если не применять макрос while(BusyUSART()); есть шанс потерять кучу первых байт.
А теперь попытаемся поэкспериментировать с нашей новой функцией и просто с выводом строки
putsUSART( (char *) "Welcome to Diymicro.ru \r\n" ); putsUSART( (char *) "The number is " ); NumToUart(1283);
И то, что получилось:
Вроде как работает, можно двигаться дальше.
Чтение.
Я юзаю pic18f14k50, у которого RB5 аналоговый канал, то есть сначала нужно выключить аналоговые буферы.
ANSEL = 0;
ANSELH = 0;
И можно работать 🙂
Как обычно есть два пути – через *опу и прерывания, но так как у нас эксперимент, мы пойдем первым путем 🙂
Считать один байт можно с помощью функции
char ReadUSART(void)
То есть, например, это можно организовать как-то так:
while(!DataRdyUSART()); rxbyte=ReadUSART(); while(BusyUSART());
И все, теперь ваш байт из уарта находится в переменной rxbyte. Опять таки нужен первый макрос, иначе регистр не очистится и в терминал постоянно будет сыпаться его содержимое (для случая работы в цикле).
Если хочется считать побольше инфы (например длинное сообщение), то можно пользоваться функцией:
void getsUSART(char *buffer, unsigned char len)
Она считает ровно ваши len байт.
Придумать как отобразить работу чтения без видео я как-то не очень смог, так что придется вам показать еще и видео (:
Здесь разместим код, того, что буду показывать:
#include <xc.h> #include <plib/usart.h> #define _XTAL_FREQ 12000000 //The speed of your internal(or)external oscillator #pragma config WDTEN = OFF, LVP = OFF, FOSC = HS unsigned char UARTConfig = 0; unsigned char baud = 0; char txbyte = 'U'; //наш байт для пересылки unsigned char Rxdata[10]; void NumToUart(unsigned int Num) //Число в уарт { unsigned int bignum = 10000; unsigned char numtemp = 5; while(numtemp>0) //Определяем сколько разрядов имеет наше число { if (Num/bignum) break; numtemp--; bignum = bignum / 10; } for (unsigned char i = numtemp; i>0; i--) { WriteUSART( (Num - (Num/(bignum*10))*bignum*10 )/bignum + '0'); //Выталкиеваем все разряды - от старшего к младшему while(BusyUSART()); //Ждем пока освободится модуль иначе будут прострелы bignum = bignum/10; } } void main() { ANSEL = 0; //Отключаем аналоговые буфера ANSELH = 0; TRISB7 = 0; //TX pin set as output TRISB5 = 1; //RX pin set as input TRISB6 = 1; //RX pin set as input UARTConfig = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ; //прерывания выключены, асинхронный режим, 8 бит, высокоскоростной режим baud = 77; //Focs/(9600*16) - 1 OpenUSART(UARTConfig,baud); WriteUSART(txbyte); //Пишем наш байт putsUSART( (char *) "\r\nputs test\r\n" ); putsUSART( (char *) "Welcome to Diymicro.ru\r\n" ); putsUSART( (char *) "The number is " ); NumToUart(1283); getsUSART(Rxdata, 10); while(BusyUSART()); putsUSART( (char *) "\r\nAll bytes have recieved, your message is - \r\n" ); putsUSART(Rxdata); putsUSART( (char *) " \r\nNow, just print what you want :) \r\n" ); while(1) { while(!DataRdyUSART()); txbyte=ReadUSART(); while(BusyUSART()); if (txbyte) { WriteUSART(txbyte); while(BusyUSART()); } }//while(1) }//main()
Ну а здесь уже собственно результат:
Ну и как обычно, исходники можно найти в репе.
я про готовую библиотеку и не подумал даже, все по минимому:
SPBRG = 77;//устанавливаем скорость для USART 9600 при 12*4=48Mhz
RCSTA = 0b10010000;//регистр состояния и управления приемника USART
TXSTA = 0b00100000;//регистр состояния и управления передатчика USART
BAUDCON = 0b01000000;
unsigned char read(void)
{
do{;}while(PIR1bits.RCIF == 0);
return RCREG;
}
void write (unsigned char tmp)
{
TXREG = tmp; //записываем байт в регистр TXREG
do{;}while(TXSTAbits.TRMT == 0);//ждем пока в TSR есть данные
}
Я в последнее время люблю все готовое 🙂
Для строки то функция где? 🙂
в компиляторе 3.46 нельзя выводить строки как обычно, например как у тебя : putsUSART( (char *) “Welcome to Diymicro.ru \r\n” );
нужно создать массив с символами,а потом выводить его.
не помню в каком проекте эксперементировал,поэтому и не написал пример.
на тот момент когда занимался USARTом в PIC18 про XC8 не знал
Не так я и говорю, что нужно тогда еще функцию по выталкиванию строки в ручную писать, чтобы уже полноценная либа была.
Но раз нам все дают готовое прямо в компиляторе, то зачем нам этот гемор? 🙂
интересно было самому написать, да и вывод строки через массив это не такая уж и проблема. не нравится мне когда много всего написано,нравится когда по минимому, пусть даже есть небольшие неудобства.плюс если пытаться самому допирать, то в других местах уже будет проще, ну конечно далеко не везде сам допираешь 🙂
а почему ты не использовал внутренний кварц? в PIC18F14K50 есть внутренний на 12MHZ
Внутренний RC в смысле?
Если да так он почти во всех есть, просто у меня привычка чтоли, что если могу заложить получше возможность, то закладываю.
не 12MHz а 16MHz.не совсем уверен что RC.тот регистр который отвечает за выбор частоты называется OSCILLATOR CONTROL REGISTER,там что то про RC совсем ни слова.
у данного мк и так портов не много, так еще и пару на кварц отдать надо
Здравствуйте.
Подскажите пожалуйста #pragma config WDTEN = OFF, LVP = OFF, FOSC = HS
так биты конфигурации настраиваются в XC8 или же #FUSES? Или и так, и так можно?
Что-то на __CONFIG у меня просто ругается…..
ПРичем если я так напишу, то при запуски проекта в более старой версии MPLAB (не X), то это будет выводиться ошибкой и там только через __CONFIG надо будет, т.к. компилятор хайтековский, а не XC8?
#pragma config – XC8
__CONFIG – hi-tech PICC compiler
Читаем мануал на XC8 и видим:
The 8-bit compilers have used the __CONFIG() macro for some targets that did not
already have support for the #pragma config.
For the 8-bit compilers, change any occurrence of the __CONFIG() macro, such as
__CONFIG(WDTEN & XT & DPROT)
to the #pragma config directive, as in
#pragma config WDTE=ON, FOSC=XT, CPD=ON
No migration is required if the #pragma config was already used
Аааа. Я ничего не понимаю на английском 🙂 Поясните пожалуйста. А почему тогда на #fuses не ругается?
А остальное все так же как и в хайтеки? include и т.д. у остального. Только вместо __CONFIG #pragma confiп?
Да, #pragma config
Не совсем все, к портам доступ по другому организован и названия регистров могут отличаться, но это все решается в считанные секунды.
Почему не ругается на фьюзы – понятия не имею, но упоминания о такой директиве нету в мануале на xc8.
Подскажите пожалуйста как мне такое написать?
__CONFIG(WDTDIS & UNPROTECT & MCLRDIS & INTOSCIO);
чтобы таймер отключить, чтоб работало от внутреннего генератора и чтоб был сброс при малом питании… Не знаю что такое LVP у Вас.
#pragma config MCLRE = OFF — так у меня нормально, но вот когда хочу другие опции записать… Все ругается….
Все, разобрался, не важно, спасибо)
Ок 🙂