Некоторые неочевидные особенности среднего семейства PIC (PIC16 и PIC18)


Разрабатывая устройства на основе микроконтроллеров PIC иногда приходится сталкиваться с каким-то, порой, совершенно невероятным поведением устройств, причём, на первый взгляд всё может выглядеть так, будто ошибок в схеме и программе никаких нет.

Разумеется, все нижеперечисленные проблемы можно объяснить невнимательным чтением документации, однако часто ситуация такова, что сроки разработки стремительно поджимают и времени на тщательное изучение спецификаций банально не остаётся. Тем не менее, есть некоторые моменты зная которые можно несколько уменьшить количество проблем, которые придётся героически преодолевать при разработке новых устройств, данный краткий обзор именно об этих проблемах.

Нижеописанное актуально для основной части МК из семейства PIC16 и PIC18, однако также могут быть и некоторые различия - если у вас не получается решить свою проблему, на всякий случай прочтите ещё раз даташит на свою модель и проверьте лишний раз код.

Беспричинные перезагрузки

При разработке плат для моделей, имеющих вывод PGM следует подтягивать этот вывод к питанию через внешний резистор 15-30 кОм. В противном случае могут наблюдаться случайные беспричинные перезагрузки контроллера. Упоминания данного факта сложно отыскать в каком-либо даташите, возможно потому что этот факт описан в каком-нибудь отдельном документе, скажем на ICSP.

-------

Зависания и проблемы с UART

При инициализации последовательного порта следует дёрнуть бит CREN:

CREN = 0;
CREN = 1;


Иначе возможны ошибки в работе порта.



Также полезно добавить куда-нибудь в цикл проверку ошибки переполнения:

if (OERR) { CREN = 0; CREN = 1; } // Сброс ошибки переполнения

-------

Задание скорости работы UART

При задании скорости UART, желательно завести привычку задавать сразу оба байта SPBRGH и SPBRG, т.к. когда понадобится в SPBRG записать значения больше char (получаются при больших Fosc для малых скоростей UART), то, если при инициализации UART писать только в SPBRG, то в SPBRGH останутся нули и скорость UART будет некорректной.

Можно делать, например, так:

// Глобальные константы
const unsigned char BRGH_STATE = 1;
const unsigned char BRG16_STATE = 1;

// В данном примере использовано значение SPBRG из даташита, равное 4165 (в десятичной системе)
const unsigned char SPBRG_H = 0x10;// Расчётное значение старшего байта SPBRG
const unsigned int SPBRG_L = 0x45;// Расчётное значение младшего байта SPBRG

// При инициализации установить требуемую скорость передачи с помощью регистра SPBRG и бита BRGH
TX9 = 0;
SYNC = 0; // Выбрать асинхронный режим сбросом бита SYNC в ‘0’
BRGH = BRGH_STATE;
BRG16 = BRG16_STATE;
SPBRGH = SPBRG_H;
SPBRG = SPBRG_L;


---------

Косяки Timer1

В Errata к PIC18F2580 написано что таймер в каких-то случаях может глючить, поэтому писать всегда следует в TRM1L сразу после TMR1H:

TMR1H = TIMER1_H;
TMR1L = TIMER1_L;
TMR1IF = 0; // Сброс флага прерывания


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

На всякий случай стоит делать так для любого 16-бит таймера.




ˆ