STM8L051F3: режимы GPIO, тактирование, энергопотребление
разделы: STM8 , дата: 23 апреля 2016г
В этот раз разберемся с портами I/O, научимся управлять рабочей частотой чипа и измерим потребление тока в Active режиме.
Я буду использовать режимы работы GPIO в AVR в качестве переводчика, для понимания терминологии SMT8.
Управление GPIO в STM8 похоже на AVR, но, как бы сказать, более логично с точки зрения здравого смысла. Однако, что бы разобраться с режимами GPIO в STM8 придется выучить новый термин: Open Drain. Замечу, что ничего нового в этом термине нет для освоивших GPIO в AVR.
Итак, в AVR портом GPIO можно было управлять двумя регистрами I/O: DDRx и PORTx; Третий регистр – PINx, был доступен только для чтения, и он ничем не управлял.
В STM8 для управления портом GPIO служат уже три регистра: Px_DDR, Px_ODR, Px_CR1. Регистр Px_IDR аналогичен PINx – он ничем не управляет. Регистр Px_CR2 служит для установки прерывания и режима тактирования GPIO, к нашей теме отношение тоже не имеет
Если в AVR только DDRx определял режим работы PORTx, то в STM8 для этого служат Px_DDR и Px_CR1, причем второй в Open Drain режиме имеет приоритет над первым.
- Как не сложно подсчитать, три регистра дают комбинацию из 8 состояний GPIO:
- Выход Push-pull или PP: (CR1=1 && DDR=1) => тогда состояние ODR задает режим GPIO. При логической единице порт подключен к шине питания, иначе – к земле.
- Вход Pull-up или точнее WPU(weak pull-up) (CR1=1 && DDR=0) значение ODR в этом состоянии ни на что не влияет. Соответствующий пин порта можно напрямую замыкать на землю, Проходящий ток у меня составил 88 мкА. Слабовато, да.
- Вход Floating или HiZ или высокоимпедансный вход. (CR1=0 && DDR=0). Здесь все ясно, думаю. Это не плюс и не минус. Значение ODR в этом состоянии также ни на что не влияет.
- Выход. Open Drain или OD. (СR1=0 && DDR=1) Последний режим GPIO сочетает в себе режимы: вход Floating(HiZ) и выход Push-Pull. При ODR=1, порт переключается в floating/HiZ режим, при ODR=0 подключается с земле.
Последний Open Drain, или вернее, pseudo Open Drain – специальный режим для работы с последовательной шиной (различные вариаций I2C, 1Wire и т.д.).
В AVR он создавался записью нуля в PORTx и переключался изменением DDRx. Такой способ приводил к инверсионной логике (запись логической единицы в DDR подключала к земле).
В STM8 такой жести нет! Ноль это ноль, а единица это “отпускание шины” до логической единицы.
Тактирование
С режимами GPIO разобрались, осталось разобраться с энергопотреблением. STM8L это линейка микроконтроллеров для батарейного питания. По идее такой микроконтроллер должен мало потреблять. Но когда запускаем L051 чип с пустой программой, получаем ток потребления 900мкн. Не слабо!
Но, это смотря с чем сравнивать. Если сравнивать с ATtiny13A, то сперва нужно опустить частоту тактового генератора до 1 МГц.
Так же как и AVR, STM8 имеет два генератора частоты. Основной – HSI и тихоходный LSI от которого тактируется watchdog. Основной генератор работает на частоте 16МГц и для тактирования основной шины использует делитель в регистре CLK_CKDIVR:
По умолчанию делитель равен 8, т.е. чип стартует на 2МГц.Пробуем изменить делитель на 16:
#define CLK_CKDIVR *(unsigned char*)0x50C0 #define PA_ODR *(unsigned char*)0x5000
#define PA_DDR *(unsigned char*)0x5002
#define PA_CR1 *(unsigned char*)0x5003 #define PB_ODR *(unsigned char*)0x5005
#define PB_DDR *(unsigned char*)0x5007
#define PB_CR1 *(unsigned char*)0x5008 #define PC_ODR *(unsigned char*)0x500A
#define PC_DDR *(unsigned char*)0x500C
#define PC_CR1 *(unsigned char*)0x500D #define PD_ODR *(unsigned char*)0x500F
#define PD_DDR *(unsigned char*)0x5011
#define PD_CR1 *(unsigned char*)0x5012 #define P7 7
#define P6 6
#define P5 5
#define P4 4
#define P3 3
#define P2 2
#define P1 1
#define P0 0 int k=0; static void delay(unsigned int t)
{ while(t–);
} int main( void )
{ PB_DDR|=(1
Источник: http://www.count-zero.ru/2016/stm8_gpio/
Урок 5. Изучаем систему тактирования микроконтроллеров STM8. — DRIVE2
Микроконтроллеры STM8 могут тактироваться от трёх источников:
Высокоскоростной внутренний RC генератор (HSI), который работает на частоте 16 МГц —
Низкоскоростной внутренний RC генератор (LSI), который работает на частоте 128KHz
Внешний RC генератор (кварц) который может работать на частоте от 1 до 24 МГц,
Во время изучения микроконтроллеров STM8 мы будем использовать внутренний генератор, который нас вполне устраивает (хочу заметить, что внутренний генератор откалиброван очень хорошо). Конечно внешний кварц давал бы нам большую точность, но до того как мы начнём делать прицензионные часы или ещё что либо, зачем нам лишние детальки на плате? .
Во время старта микроконтроллера, если мы не вносили никакие изменения в регистры, наш внутренний генератор будет работать на частоте 2МГц. Мы же изменим настрой делителя частоты, чтобы наш внутренний генератор начал работать на частоте 16МГц
Алгоритм настройки нашего генератора таков:-Сброс всех регистров генератора к их начальному значению-Выбор источника тактирования-Включение механизма тактирования
— Ожидание стабилизации системы тактирования микроконтроллера
Регистры системы тактирования
Описание регистров часов начать вокруг странице 89 STM8S Reference Manual. В этой статье мы будем запускать через регистры обогатительных от значений мы будем устанавливать. Для описания полного вы должны обратиться к STM8S Reference Manual.
CLK_ICKR – Регистр внутреннего тактирования (Internal Clock Register)
Имя регистра/ Описание
REGAH / Контроль за действиями регулятора внутреннего напряжения, когда чип входит в режим Active-Halt.
LSIRDY/ Устанавливается аппаратно, это бит указывает, готов и стабилен ли LSI.
0 — указывает осциллятор не готов, 1 — указывает, что осциллятор стабилен
LSIEN/ Этот бит определяет, выбран ли в качестве источника синхронизации для микроконтроллера.
FHWU/ Этот бит можно менять в самой программе. Это бит показывает включено ли быстрое пробуждение из Active-Halt режима.
0=отключено, 1=включено
HSIRDY/ Устанавливается и сбрасывается аппаратно, это бит определяет, стабилен и готов к использованию ли внутренний источник тактирования HSI.
HSIEN/ Этот бит можно менять в самой программе. Он определяет, выбран ли HSI в качестве источника тактирования.
Также этот бит может быть установлен аппаратно, если требуется принудительная работа от HSI. 0=указывает что HSI не выбран, 1=указывает что HSI выбран.
CLK_ECKR – Регистр внешнего тактирования (External Clock Register)
Имя регистра / Описание
HSERDY/ Состояние внешнего источника тактирования. 0=не готов, 1= готов.
HSEEN/ Включениеотключение внешнего источника тактирования. 0= отключено, 1= включено
CLK_CMSR – Регистр состояния тактового генератора (Clock Master Status Register)Этот регистр устанавливается и сбрасывается аппаратно и указывает, какой из генераторов выбран в качестве источника тактового сигнала.Величина Источник тактирования
0xe1 HSI
0xd2 LSI
0xb4 HSE
CLK_SWR – Регистр переключения системного источника тактированияЭтот регистр может изменятся в пользовательской программе и используется для выбора источника тактирования.Величина Источник тактирования
0xe1 HSI
0xd2 LSI
0xb4 HSE
CLK_CKDIVR — делитель системной тактовой частотыСистемный тактовый сигнал может быть разделён, чтобы обеспечить более низкую частоту работы ядра микроконтроллера. Этот регистр позволяет установить предделитель для внутреннего источника тактирования (HSI) и предделитель для ядра микроконтроллера .Имя регистра /Описание
HSIDIV/ Предделитель внутреннего генератора
CPUDIV/ Предделитель частоты ядра
Вот такие значения могут быть использованы в качестве предделителя HSIЗначение / Предделитель0 / Частота HSI1 / Частота HIS разделённая на 22 / Частота HIS разделённая на 4
3 / Частота HIS разделённая на 8
Вот такие значения могут быть использованы в качестве предделителя для ядра.Значение / Предделитель0 / Тактовая частота1 / Тактовая частота разделённая на 22 / Тактовая частота разделённая на 43 / Тактовая частота разделённая на 84 / Тактовая частота разделённая на 165 / Тактовая частота разделённая на 326 / Тактовая частота разделённая на 64
7 / Тактовая частота разделённая на 128
CLK_PCKENR1 & CLK_ PCKENR2 – Регистры для тактирования всей периферии
Эти регистры нужны для того, чтобы подавать тактирование на нужную нам периферию – таймеры, биперы, I2C и прочее. Для каждого периферийного устройства там отводится по одному биту. Установленный в единицу бит разрешает тактирование, а сброшенный в ноль — отключает тактирование.
Название регистра / Периферия / Описание
CLK_PCKENR1 / TIM1 / Включение / отключение таймера 1TIM3 Включение / отключение таймера 2TIM2/TIM5 Включение / отключение таймера 2/5 (зависит от мк.)TIM4/TIM6 Включение / отключение таймера 4/6 (зависит от мк.)UART1/2/3 Включение / отключение UART 1/2/3SPI Включение / отключение SPII2C Включение / отключение I2C
CLK_PCKENR2 / CAN / Включение / отключение CAN шину
ADC Включить / отключить АЦП
AWU Включить / отключить сторожевой таймер
Включённая периферия будет использовать частоту тактового генератора. Отключение тактирования собой службы – отключает её.
CLK_CSSR – Регистр системы безопасностиПосле включения, CSS начинает пристально следить за тактовым сигналом от HSE.
Если он вдруг прервался, выполняются следующие спасательные мероприятия:— Запускается HSI (если он выключен)и тактирование переключается на него— HSE выключается— В CLK_CSSR поднимается флаг AUX, оповещая нас о том, что работает запасной генератор.
— Там-же поднимается флаг CSSD и, если установлен бит CSSDIE, происходит прерывание.
— Все регистры из группы CLK, кроме CLK_CKDIVR, блокируются для записи. Изменить настройки тактирования (кроме делителя) больше нельзя до следующей перезагрузки.
CLK_CCOR – Настраиваемый регистр вывода тактовой частотыСлужит ля вывода тактового сигнала на ножку МК.
CLK_HSITRIMR — Калибровка внутреннего генератора
Ну и теперь маленький пример, который показывает как мы можем работать с системой тактирования.
Для примера, мы просто будем инвертировать состояние пина PD0, и при этом менять настройки тактирования, и на осциллографе будем наблюдать за изменением частоты при установке предделителя.
Вот наш код программы
____________________________________________________________#include
#include
//// Устанавливаем частоту работы микроконтроллера 16 МГц от внутреннего генератора//void InitialiseSystemClock(){CLK_ICKR = 0; // Сбрасываем регистр внутреннего тактированияCLK_ICKR_HSIEN = 1; // Включаем внутренний генератор HSICLK_ECKR = 0; // Отключаем внешний генераторwhile (CLK_ICKR_HSIRDY == 0); // Ждём стабилизации внутреннего генератораCLK_CKDIVR = 0; // Устанавливаем максимальную частотуCLK_PCKENR1 = 0xff; // Включаем всю перифериюCLK_PCKENR2 = 0xff; // Тоже самоеCLK_CCOR = 0; // Выключаем CCO.CLK_HSITRIMR = 0; // Turn off any HSIU trimming.CLK_SWIMCCR = 0; // Set SWIM to run at clock / 2.CLK_SWR = 0xe1; // Используем HSI в качестве источника тактировCLK_SWCR = 0; // Сброс флага переключения генераторовCLK_SWCR_SWEN = 1; // Включаем переключение на HSIwhile (CLK_SWCR_SWBSY != 0); // Пауза, пока произойдёт переключение
Читайте также: Устройство защиты ламп накаливания на avr
}
//////int main(void){__disable_interrupt(); //запрещаем прерывания намомент инициализации//// Инициализируем нашу ножку PD0//PD_DDR_DDR0 = 1; // Устанавливаем пин PD0 на выходPD_CR1_C14 = 1; // Пин работает в режиме push-pullPD_CR2_C24 = 1; // Частота работы пина до 10МГц//// Now setup the system clock//InitialiseSystemClock();__enable_interrupt(); //Разрешаем прерыванияwhile (1)//Бесконечный цикл переключения нашего пина{PD_ODR_ODR4 = 1; // Выдаём единицу (+5В) на пин PD0PD_ODR_ODR4 = 0; // Выдаём ноль (массу) на пин PD0}
}
_______________________________________________________________
После подключения осциллографа к нашему пину PD0 мы увидим вот такую картинку. Частота переключения нашего пина – 2,963МГц. (Хочу заметить, что вы никогда не увидите частоту 16МГц на пине, поэтому в нашем примере -частота 2,963МГц, просто показательная, и меняя предделитель частоты, мы увидим как именно она будет меняться)
А теперь, вот что произойдёт, если мы установим предделитель для внутреннего генератора (HSI) равный 2 .Для этого нам нужно изменить вот эту строчку нашего кода.___________________________________________________________
CLK_CKDIVR = 0
______________________________________________________
На вот это______________________________________________________
CLK_CKDIVR = 0;
CLK_CKDIVR_HSIDEV = 1; //Устанавливаем предделитель равный 2
______________________________________________________
Результат нашей работы на картинке ниже. Частота сигнала стала 1,335МГц, то есть около половины нашей первоначальной частоты.
Прошу прощения за некоторые плохо читаемые участки статьи с кодом. Просто драйв2 не позволяет нормально работать с таблицами и форматированием текста.
Спасибо за внимание. Жду лайков и комментариев.
Источник: https://www.drive2.ru/b/1323875/
Начало работы с микроконтроллерами STM8, Матюшов Н.В. 2016г
Дата публикации: 13 августа 2018.
Серия STM8S является основной, так как она «перекрывает» большинство применений восьмиразрядных микроконтроллеров.
Микроконтроллеры серии STM8S основаны на архитектуре STM8, построены по технологии 130 нм, что позволяет им работать на частотах до 24 МГц.
Наличие встроенной памяти EEPROM, внутренних источников тактового сигнала и большого набора периферийных модулей позволяют использовать эти микроконтроллеры во многих встраиваемых приложениях.
Серия STM8S состоит из четырех линеек:
— STM8S003/005/007 — линейка «Value line» — микроконтроллеры «начального» уровня с базовым набором функций — имеют малое допустимое количество перезаписи памяти программ;— STM8S103/105 — линейка « Access line» — имеют больше функций, памяти, большее количество циклов перезаписи памяти;— STM8S207/208 — линейка «Performance line» — имеют полный набор функций;
— STM8S903 — линейка микроконтроллеров специального назначения.
Линейки обладают различными функциями, но, тем не менее, между ними сохранена совместимость «Корпус в корпус», что позволяет при необходимости переходить на более производительные микроконтроллеры простой заменой.
Оглавление
Глава 1. Общая информация о микроконтроллерах STM8Обозначение микроконтроллеровДокументация Отладочная плата STM8S-Discovery
Характеристики микроконтроллера STM8S105C6T6
Глава 2. Порты ввода — вывода STM8SОсновные возможности портов ввода-вывода:Структурная схема линии порта ввода — выводаОсобенности работы портовРабота линии порта с аналоговыми сигналами
Регистры портов ввода — вывода
Глава 3. Контроллер прерываний Таблица векторов прерыванийОбработка прерывания Программный и аппаратный приоритет прерыванийПоследовательность обработки прерыванийРежимы управления прерываниями Внешние прерывания
Регистры контроллера прерываний
Глава 4. Система энергосбережения Режим энергосбережения WAIT Режим энергосбережения HALT
Режим энергосбережения Active HALT
Глава 5. Система тактирования Источники тактовой частотыПереключение основного источника тактового сигналаУправление тактированием периферийных модулей Система защиты тактирования Вывод тактового сигнала
Регистры модуля тактирования:
Глава 6. Независимый сторожевой таймер
Регистры IWDG:
Глава 7. Оконный сторожевой таймер
Регистры модуля WWDG
Глава 8. Система сброса
Регистры модуля сброса
Глава 9. Модуль автоматического пробуждения (AWU)
Регистры модуля AWU
Глава 10. Таймеры Обзор таймеров STM8 Основные возможности таймера 1Функциональная схема таймера 1Формирователь временных интерваловРежимы счетаСчетчик повторенийВзаимодействие между таймерамиКаналы захвата/сравнения таймера 1 Режимы работы таймера 1
Регистры таймера 1
Глава 11. Таймер 2
Регистры таймера 2
Глава 12. Таймер 4
Глава 13. Модуль SPI
Описание регистров модуля SPI
Глава 14. Модуль UARTСтруктурная схема модуля UART
Регистры модуля UART
Глава 15. Интерфейс IIC
Регистры интерфейса IIC
Глава 16. Аналого-цифровой преобразователь stm8Структурная схема модуля АЦПОписание работы АЦПТактирование АЦПВыбор каналовРежимы преобразованияПрерывания АЦП
Аналоговый компаратор
Глава 17. Модуль звукового излучателя
Глава 18. Электрические характеристики stm8
Глава 19. Память
Глава 20. Список использованных источников
Скачать с Depositfiles
Печать E-mail
Авторизация
Источник: https://radioparty.ru/literatura/678-nachalo-raboty-s-mikrokontrollerami-stm8-matyushov
SDCC для STM8. Таймер и обработка прерываний
В прошлой статье я рассказал про то, как установить компилятор SDCC в linux и как с помощью него собрать код на C для STM8, а также поделился библиотекой работы со стандартной периферий STM8S, которая поддерживает SDCC. Сегодня я хочу представить еще один пример, в котором будет использован таймер. В примере мы объявим обработчик прерывания для таймера и выполним в нем переключение состояния светодиодов.
Я буду использовать ту же библиотеку что и в прошлый раз. При внесении изменений для поддержки SDCC в библиотеку я постарался сделать это так, что бы код написанный под SDCC не отличался от кода для других компиляторов. По этому этот же пример с этой же библиотекой должен точно так же компилироваться под IAR EWSTM8, COSMIC и RAISONANCE.
В основном из библиотеки я буду использовать только файл stm8s.h, в котором на низком уровне описана периферия. Если вы знакомы с организацией библиотек стандарта CMSIS для ARM, то этот файл можно сравнить с периферийным описанием из CMSIS(например stm32f10x.h или LPC17xx.h).
Один этот файл уже сам по себе представляет хорошую низкоуровневую библиотеку с регистрами в виде полей структур отображенных на память периферии. Остальная часть библиотеки Standard peripheral library это более высокоуровневая прослойка для работы с периферией в более удобном виде, так называемые драйвера периферии.
Внутри драйверы реализованы с использованием stm8s.h, то есть они дополняют библиотеку низкоуровневой периферии а не являются её заменой.
Организованы эти драйверы точно таким же образом как и библиотека стандартной периферии для STM32: так же состоит из хедеров и файлов реализации по имени периферийного модуля, такие же примеры, те же самые assert_failed, про которые я рассказывал тут, и вообще очень много похожего.
Но использовать драйвера для периферии в STM8 я пока не тороплюсь: во-первых при их использовании теряется производительность за счет огромного числа проверок, и если в STM32 это еще можно было себе позволить, то в крохотных STM8 это выглядит по меньшей мере расточительно, во-вторых сами драйвера – это часто лишние вызовы не inline-овых функций, что приводит к лишним jamp-ам в конечном коде, в третьих сам код внутри драйвера не всегда написан так, как хотелось бы, какие-то действия вовсе лишние, а какие-то можно было бы сделать иначе. Но большим преимуществом библиотеки драйверов является пачка примеров, которые также я есть в архиве, данном в прошлой статье. Они хоть и используют драйвера, но показывают как работать с периферией и их можно легко переписывать под низкоуровневый stm8s.h, подглядывая реализацию нужных функций в драйвере и переписывая её себе.
Итак пример с таймером. Задача: реализовать перемигивание светодиодов раз в секунду.
Код(я создал файл timer.c в той же директории где у меня leds.h):
#include “stm8s.h”
//stm8s_gpio.h – заголовочный файл из драверов, в примере я его подключил исключительно для дефайнов GPIO_PIN_х
#include “stm8s_gpio.h”
int main( void )
{ GPIOC->DDR |= GPIO_PIN_3 | GPIO_PIN_4; //Настраиваем пины PС3 и PС4 на выход GPIOC->CR1 |= GPIO_PIN_3 | GPIO_PIN_4; //И включаем для них режимPush-pull GPIOC->ODR |= GPIO_PIN_3; //Зажигаем светодиод на PC3 /* Инициализация тактирования */ // Тактирование МК от внутреннего высокочастотного кварца(HSI) 16 MHz // Частота CPU и периферии 16 MHz / 2 = 8 MHz CLK->CKDIVR &= (uint8_t)(~CLK_CKDIVR_HSIDIV); CLK->CKDIVR |= (uint8_t)CLK_PRESCALER_HSIDIV2; /* Настройка таймера TIM2: – TIM2CLK = 8 MHz, Предделитель выберем равный 128, тогда счетчи будет считать с частотой 8 MHz / 128 = 62500 Hz Одна секунда пройдет когда счетчик насчитает TIM2_ARR: */ #define TIM2_ARR ((uint16_t)(1 * 62500 – 1)) TIM2->PSCR = (uint8_t)(TIM2_PRESCALER_128); //Настройка предделителя /* Настройка значения по которуму будет выполнятся сброс счетчика таймера */ TIM2->ARRH = (uint8_t)((TIM2_ARR>>8)& 0xFF); TIM2->ARRL = (uint8_t)((TIM2_ARR & 0xFF)); TIM2->SR1 = (uint8_t)(~TIM2_FLAG_UPDATE); // очистка флага прерывания TIM2 UPDATE TIM2->IER |= (uint8_t)TIM2_IT_UPDATE; //включение прерывания TIM2 UPDATE enableInterrupts(); //глабально разрешаем прерывания TIM2->CR1 |= TIM2_CR1_CEN; //запуск счета таймера while(1);
}
/* Объявляем обработчик прерывания по вектору 13 */
INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
{ GPIOC->ODR ^= GPIO_PIN_3 | GPIO_PIN_4; //инвертируем состояния светодиодов TIM2->SR1 = (uint8_t)(~TIM2_IT_UPDATE); // очистка флага прерывания TIM2 UPDATE
}
В коде вроде все что нужно прокоментированно, если что-то непонятно, спрашивайте в комментариях – постараюсь объяснить в подробностях.
Для сборки я использовал Makefile из прошлой статьи, только изменил 5ую строку следующим образом:
SOURCE=timer
Подключение программатора к плате точно такое же как и в прошлой статье.
Источник: https://bovs.org/post/112/
Использование CAN в STM8
Вместе с компилятором Raisonance и средой разработки Ride7 поставляется библиотека периферийных устройств для STM8S. У меня она находится по адресу:
“C:Program FilesRaisonanceRideExamplesSTM8ST_LibrariesSTM8A-S_StdPeriph_Lib-v2.0.0LibrariesSTM8S_StdPeriph_Driver”
Так вот там есть файл stm8s_can.c, а в нём всё необходимое для работы с CAN. Напомню, что такое CAN.
Это такая последовательная пакетная широковещательная сеть, по-английски назыавется Controller Area Network. В сети передаются маленькие пакеты, максимум 8 байт.
У них есть идентификаторы, длиной 11 бит (стандартные) или 29 бит (расширенные). Я рассматриваю только вариант, где используются стандартные идентификаторы.
Кроме того, пакеты бывают двух видов — обычный пакет, и запрос на передачу. Запрос это такой пакет, где выставлен бит RTR (remote transmission request).
Настройка
Чтобы работать с CAN, микроконтроллер должен брать частоту из внешнего кварца. Иначе модуль CAN не работает. Поэтому ставим кварц, настраиваем STM8 на работу от внешнего кварца, как описано здесь. В конец функции Init_CPU() добавляем настройку предделителя CAN:
CLK_CANConfig( CLK_CANDIVIDER_1 );
Выводы процессора CAN_TX и CAN_RX нужно настроить на вывод и ввод.
// CAN_TX GPIO_Init( GPIOG, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST ); // CAN_RX GPIO_Init( GPIOG, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT );
Внизу будет ссылка на проект с описываемыми в этой статье исходниками для отладочной платы Reva v3.3. Я использую вот такую дочернюю плату STM8S208RB. В ней, чтобы заработал CAN, нужно организовать внешнюю частоту.
Для этого на дочернюю плату можно проводком завести частоту 12 МГц, которая берётся с платы Reva (найдёте на плате пин, который соответствующим образом маркирован). Куда его заводить? На дочерней плате есть шесть «дырок» в левой части, как раз под установку кварца.
Проводок можно воткнуть в правую нижнюю дырку, и всё заработает. У меня работает такая схема.
Ещё, на этой плате есть CAN Transiever. Чтобы работал CAN, нужно ещё и его включить. Делается это одной так:
Читайте также: Имитатор звука сирены
// Configure the CAN transceiver in active mode GPIO_Init( GPIOE, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST );
Инициализация
Дальше идёт инициализация модуля CAN. Полный исходный код смотрите в проекте, ссылка на которой расположена в конце статьи. Здесь покажу только основные строчки, на которые надо обратить внимание.
Параметры, влияющие на частоту передачи в шине CAN:
Параметры ниже подобраны мной для частоты передачи 25 КГц, в то время как частота микроконтроллера 12 МГц (а предделитель CAN равен 1, т.е. те же 12 МГц). Если эти параметры изменятся, то и следующие строчки тоже придётся менять, подбирать параметры заново.
Вычисляется это так: QUANTA = (1 + BitSeg1 + BitSeg2) CAN_FRQ = CPU_FRQ / (Presc * QUANTA)
Допустим, хотим частоту CAN 25 КГц, и частота процессора 12 МГц.
25000 = 12000000 / (Presc * QUANTA)
Надо подобрать такую (Presc * QUANTA), чтобы при делении 12 МГц на это число, получалась частота CAN 25 КГц.
При вычислении QUANTA нужно иметь в виду, что BitSeg1 может быть в пределах от 1 до 16, а BitSeg2 в пределах от 1 до 8. QUANTA должна получиться в диапазоне от 8 до 25. В нашем случае (Presc * QUANTA) равно 480.
Допустим, выбрали BitSeg1 равным 7, а BitSeg2 равным 2. Тогда QUANTA = (1 + 7 + 2) = 10. Теперь узнаем значение предделителя. (Presc * QUANTA) должно равняться 480. Значит Presc равен 48.
Получаем такие строчки инициализации:
// 25 КГц CAN_SynJumpWidth = CAN_SynJumpWidth_1TimeQuantum; CAN_BitSeg1 = CAN_BitSeg1_7TimeQuantum; CAN_BitSeg2 = CAN_BitSeg2_2TimeQuantum; CAN_Prescaler = 48;
Фильтры
Теперь о фильтрах. Фильтры нужны для того, чтобы микроконтроллер не тратил процессорное время на обработку всех приходящих по шине сообщений. Ведь их может быть довольно много, а микроконтроллер должен обрабатывать только какие-то конкретные сообщения с известными ему идентификаторами. Остальные надо фильтровать.
Приведу один возможный пример фильтрации: 8-битный режим фильтрации по списку идентификаторов. Фильтрация в этом режиме возможна по битам 3-10 стандартного идентификатора. В следующем коде у идентификатора 0x5FC сдвигом отбрасываются три младших бита.
Не смотрите на то, что другие переменные содержат в названии «mask». В этом режиме все они содержат биты идентификаторов, а не маски. Названы они так для того, чтобы можно было просто и незатейливо использовать их же для другого режима, где эти маски есть.
CAN_FilterNumber = 0; CAN_FilterActivation = ENABLE; CAN_FilterMode = CAN_FilterMode_IdList; CAN_FilterScale = CAN_FilterScale_8Bit; CAN_FilterID1 = (0x5FC >> 3); CAN_FilterIDMask1 = 0; CAN_FilterID2 = 0; CAN_FilterIDMask2 = 0; CAN_FilterID3 = 0; CAN_FilterIDMask3 = 0; CAN_FilterID4 = 0; CAN_FilterIDMask4 = 0;
Таким образом, пропускаются только сообщения с идентификатором 0x5FC, и те, которые отличаются от него тремя младшими битами. Все остальные сообщения не пропускаются. Добавлять другие разрешённые идентификаторы следует в остальные CAN_FilterID*.
Отправка сообщений
Отправляются сообщения так: формируется пакет и отправляется, что тут ещё скажешь? Я использую такую функцию:
CAN_TxStatus_TypeDef CAN_Send(u16 uId, bool uRtr, u8 uLen, const void* const pData) { CAN_TxStatus_TypeDef TxStatus; CAN_TransmitMailBox_TypeDef TransmitMailbox; u16 uSendLimit; if (!uRtr) { if (0 == uLen || uLen > 8 || NULL == pData) return CAN_TxStatus_Failed; } TransmitMailbox = CAN_Transmit(uId, CAN_Id_Standard, uRtr ? CAN_RTR_Remote : CAN_RTR_Data, uLen, (u8*)pData); uSendLimit = 0xFFF; // Ограничение, чтобы не зависнуть на передаче do { TxStatus = CAN_TransmitStatus(TransmitMailbox); } while (TxStatus != CAN_TxStatus_Ok && uSendLimit–); if (TxStatus != CAN_TxStatus_Ok) { printf(“CAN: передача сообщения не удалась и отменена.
“); CAN_CancelTransmit(TransmitMailbox); } else { printf(“CAN: Успешная передача сообщения.
“); } return TxStatus; }
Получение сообщений
Принимаются сообщения в прерывании CAN. Прерывание будет наступать только по приходу сообщений, которые успешно преодолели фильтр. Прерывание выголядит так:
void CAN_RX_IRQHandler(void) interrupt 8 { u8 i; CAN_Receive(); CanMsgIn.id = CAN_GetReceivedId(); CanMsgIn.rtr = CAN_GetReceivedRTR(); CanMsgIn.len = CAN_GetReceivedDLC(); for (i = 0; i < CanMsgIn.len; i++) { CanMsgIn.dat[i] = CAN_GetReceivedData(i); } CAN_PrintMsg(); }
Дальше у меня тут вызывается CAN_PrintMsg(), которая просто выводит пришедшее сообщение на UART.
void CAN_PrintMsg(void) { u8 i; if (!CanMsgIn.rtr) { printf(“ИД: %04X Длина: %d RTR: %d Данные:”, CanMsgIn.id, (int)CanMsgIn.len, (int)CanMsgIn.rtr ? 1 : 0); for (i = 0; i < CanMsgIn.len; i++) { printf(" %02X", (int)CanMsgIn.dat[i]); } } else { printf("ИД: %04X Длина: %d RTR: %d ", CanMsgIn.id, (int)CanMsgIn.len, (int)CanMsgIn.rtr ? 1 : 0); printf("(Запрос сообщения)"); } printf(" "); }
Проект
Скачать пример работы с CAN для STM8S: stm8-can.zip (189 Кб).
система комментирования CACKLE
Источник: http://hex.pp.ua/stm8-can.php
Alex_EXE
STM32. 5. Символьный дисплей HD44780
Для работы всем контроллерам, процессорам, цифровым электронным устройствам необходим источник тактовых импульсов.
Он может быть как внешний в виде RC цепочки, керамического или кварцевого осциллятора, кварцевого генератора, также может находиться внутри контроллера. STM32 тут не исключение.
Данный контроллер имеет множество вариантов тактирования и обладает гибкими и широкими настройками управления тактированием своей периферии.
STM32 и источники тактовых сигналов
https://www.youtube.com/watch?v=XP2gMZ_kP38
Рассматривать настройку тактирования будем на примере контроллера STM32F100RB, установленного на STM32vlDiscovery. В работе будет использована библиотека Standard Peripheral Library.
Для начала посмотрим на схемы тактирования из даташитов различных контроллеров из семейства stm32.
Деревья тактирования stm32f030xx и stm32f051xx
Деревья тактирования stm32f103xx и stm32f407xx
Дерево тактирования STM32F100xx
Из дерева тактирования контроллера видно, что у него есть две основные цепи тактирования основная (системная) и часовая. Причём обе цепи могут получать тактирования как от внешнего источника тактового сигнала, так и от встроенной RC цепочки.
Встроенные RC цепочки позволяют уменьшить количество компонентов в устройстве, меньше потребляют, чем при использовании внешнего источника тактового сигнала, но отличаются малой точностью и имеют температурный дрейф (те или иные отклонения в зависимости от окружающей температуры).
Если устройство работает с точной высокоскоростной периферией, то это не лучший вариант.
Внешний источник тактовых сигналов отличается большей точностью и стабильностью, но при этом увеличивает количество компонентов, следовательно стоимость устройства и его габариты, но при этом, повторюсь, незаменим, когда требуется высокая точность и стабильность.
Системное тактирование
Рассмотрим тактирование системной части контроллера. Нам доступна встроенная 8МГц RC цепочка HSI. Для работы с ней её для начала нужно включить.
RCC_HSICmd(ENABLE);
Тактирование с неё можно подать напрямую на системную шину SYSCLK
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
в этом случае настройка тактирования основной части будет завершена и тактовая частота системной шины составит 8МГц, чего для простых задач будет вполне достаточно. Так же можно подать тактирование на системную шину через множитель PLLMUL. Для этого нам нужно его включить, выбрать множитель и источник тактового сигнала.
RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_4); RCC_PLLCmd(ENABLE);
Рассмотрим поподробнее. Первая команда RCC_PLLConfig — имеет два параметра, первый выбирает источник тактирования, для STM32F100xx доступны 2 варианта:
- RCC_PLLSource_HSI_Div2 — с внутренней HSI RC цепочки 8МГц деленные на 2, т.е. 4МГц.
- RCC_PLLSource_PREDIV1 — тактовый сигнал с внешнего тактового генератора, прошедший через предделитель PREDIV1, который рассмотрим ниже.
Второй параметр выбирает множитель:
- RCC_PLLMul_2
- RCC_PLLMul_3
- RCC_PLLMul_4
- RCC_PLLMul_5
- RCC_PLLMul_6
- RCC_PLLMul_7
- RCC_PLLMul_8
- RCC_PLLMul_9
- RCC_PLLMul_10
- RCC_PLLMul_11
- RCC_PLLMul_12
- RCC_PLLMul_13
- RCC_PLLMul_14
- RCC_PLLMul_15
- RCC_PLLMul_16
Т.е. мы можем имеющиеся 4МГц умножить в 2-6 раз, т.к. максимальная частота системной шины для используемого в примере камня 24МГц. Есть контроллеры с 32, 72, 180МГц. Но за частотой гнаться не нужно, для каждой задачи лучше использовать свою частоту.
Для простых задач вполне хватит малых частот, для ресурсоёмких и вычислительноемких задач частота нужна будет поболее. Также следует учитывать, что с возрастанием частоты увеличивается энергопотребление, тепловыделение и снижается надёжность, повышаются требования к схемотехнике и разводке.
Всегда нужно уметь находить золотую середину.
Вернёмся к командам: вторая команда RCC_PLLCmd включает или выключает PLL множитель и имеет всего два значения ENABLE и DISABLE.
Остается только выбрать источником тактирования системной шины PLLCLK.
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
Таким образом получаем тактовую частоту 16МГц, т.е. RC HSI 8МГц/2*4(множитель PLLMUL)=16МГц.
Так же поподробнее рассмотрим команду RCC_SYSCLKConfig. Данная команда, как уже было сказано выше, выбирает источник тактирования системной шины. Доступно их 3:
Если использовать внешний источник тактовых импульсов, то для начала нам нужно его подключить к контроллеру.
- RCC_SYSCLKSource_HSI — напрямую от внутренней RC HSI 8МГц цепочки
- RCC_SYSCLKSource_PLLCLK — от PLLMUL множителя
- RCC_SYSCLKSource_HSE — напрямую от внешнего осциллятора
Подключение кварцевого резонатора к stm32
Частота резонатора может быть от 4 до 24МГц. Емкость конденсаторов рекомендуется от 5 до 25пФ, подробнее нужно смотреть в документации к резонатору. В качестве резонатора можно применять: кварцевые резонаторы, кварцевые генераторы, керамические резонаторы.
Далее подключаем его в коде.
RCC_HSEConfig(RCC_HSE_ON);
Затем снова возвращаемся к выбору: подать тактовый сигнал на системную шину напрямую
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
или через множитель PLLMUL. Правда сначала сигнал пройдёт еще через предделитель PREDIV1, что существенно расширяет диапазон частот системной шины.
RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div1); RCC_PLLConfig(RCC_PLLSource_PREDIV1 ,RCC_PLLMul_3);
Данная конфигурация позволяет получить 24МГц от внешнего осциллятора:
8МГц / 1 (предделитель PREDIV1) *3 (множитель PLLMUL) = 24МГц.
Рассмотрим поподробнее предделитель PREDIV1 — RCC_PREDIV1Config. Он принимает 2 параметра: источник тактирования и делитель. Источник тактирования для STM32F100RB доступен только один RCC_PREDIV1_Source_HSE. Делителей же поболее:
- RCC_PREDIV1_Div1
- RCC_PREDIV1_Div2
- RCC_PREDIV1_Div3
- RCC_PREDIV1_Div4
- RCC_PREDIV1_Div5
- RCC_PREDIV1_Div6
- RCC_PREDIV1_Div7
- RCC_PREDIV1_Div8
- RCC_PREDIV1_Div9
- RCC_PREDIV1_Div10
- RCC_PREDIV1_Div11
- RCC_PREDIV1_Div12
- RCC_PREDIV1_Div13
- RCC_PREDIV1_Div14
- RCC_PREDIV1_Div15
- RCC_PREDIV1_Div16
Приведу итоговые коды настроек тактирования воедино:
Для тактирования от встроенной RC HSI 8МГц цепочки напрямую. SYSCLK=8МГц
RCC_DeInit(); // сброс настроек тактового генератора RCC_HSEConfig(RCC_HSE_OFF); // отключение внешнего тактового генератора RCC_HSICmd(ENABLE); // включение внутреннего RC HSI 8МГц генератора RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); // На системную шину подаем тактирование с RC HSI 8МГц
Тактирование от встроенной RC HSI 8МГц цепочки через множитель PLLMUL. SYSCLK=16МГц
RCC_DeInit(); // сброс настроек тактового генератора RCC_HSEConfig(RCC_HSE_OFF); // отключение внешнего тактового генератора RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_4); // тактирование от HSI с делителем 2: 8 / 2 * 4 = 16МГц RCC_PLLCmd(ENABLE); // Включаем PLL RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // На системную шину подаем тактирование с множителя PLLMUL
Тактирование от внешнего источника тактового сигнала напрямую. SYSCLK=8МГц
RCC_DeInit(); // сброс настроек тактового генератора RCC_HSICmd(DISABLE); // выключение внутреннего RC HSI 8МГц генератора RCC_HSEConfig(RCC_HSE_ON); // включение внешнего тактового генератора RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); // На системную шину подаем тактирование с внешнего резонатора
Читайте также: Блок питания 0…30в/5а с цифровой индикацией напряжения и тока
Тактирование от внешнего осциллятора через предделитель PREDIV1 и множитель PLLMUL. SYSCLK=24МГц
RCC_DeInit(); // сброс настроек тактового генератора RCC_HSICmd(DISABLE); // выключение внутреннего RC HSI 8МГц генератора RCC_HSEConfig(RCC_HSE_ON); // включение внешнего тактового генератора RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div1);// Предделитель PREDIV1: HSE перед множителем PLLMUL RCC_PLLConfig(RCC_PLLSource_PREDIV1 ,RCC_PLLMul_3); // тактирование от HSE с PREDIV1 8/1*3 = 24МГц RCC_PLLCmd(ENABLE); // Включаем PLL RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // На системную шину подаем тактирование с множителя PLLMUL
А вот после настройки тактирования системной шины начинается настройка тактирования уже отдельных блоков периферии, на каждый из которых нужно подать тактирование отдельно. Тактирование каждого узла периферии будет рассматриваться отдельно для каждого узла в соответствующей ему статье.
Отмечу, что есть некоторые периферийные узлы, которые тактируются от некоторых источников тактового сигнала напрямую и для их работы нужный им источник тактирования нужно будет включать в любом случае, даже если шина, для которой они предназначены, уже подключена к другому источнику.
Например, ответвление от 8МГц HSI RC цепочки FLITFCLK — это тактирование интерфейса доступа к flash памяти контроллера из его программы. Ему HSI необходима, даже если контроллер тактируется от внешнего кварца.
Подробнее это будет рассмотрено в статье по доступу к flash памяти контроллера.
Бывают случаи, когда тактовая частота шины превышает частоту тактирования подключенной к ней периферии. Обычно такая периферия снабжается собственными предделителями, которыми следует воспользоваться, чтобы периферия могла корректно работать.
Для контроля системной шины и её источников тактирования у контроллера есть специальный выход тактового сигнала — MCO. Его включение и выбор проверяемого тактового источника выбирается следующей командой — RCC_MCOConfig с параметром:
- RCC_MCO_NoClock — выключен
- RCC_MCO_SYSCLK — выход тактирования с системной шины SYSCLK
- RCC_MCO_HSI — выход тактирования с 8МГц HSI RC цепочки
- RCC_MCO_HSE — выход тактирования с внешнего основного осциллятора
- RCC_MCO_PLLCLK_Div2 — выход тактирования с множителя PLLCLK деленный на 2
Выход тактового сигнала MCO расположен на PA8 у STM32F100RB. Так же данный вывод нужно сконфигурировать на выход следующим образом.
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // включаем тактирование порта A GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // Настраиваем PA8 на выход тактирования с ситемной шины GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // альтернативный выход с подтяжкой GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // высокоскоростная работа 50МГц GPIO_Init(GPIOA, &GPIO_InitStructure); // инициализация вывода порта RCC_MCOConfig(RCC_MCO_SYSCLK); // включаем выход татирования с ситемной шины на вывод MCO (RA8)
После включения MCO получаем с PA8 синусоиду с частотой выбранной шины.
Часовое тактирование.
Как и с системным тактированием тут у нас то же доступно и встроенная LSI RC цепочка на 40КГц, так и возможность подключения внешнего часового кварца LSE, на 32.768КГц.
Плюс дополнительным бонусом можно подать тактирование через 128 кратный предделитель тактирования с внешнего основного HSE осциллятора. Это может быть полезно при использовании основного тактового генератора с кратной часовой частотой.
Наиболее распространённый и точный вариант — использование внешнего часового кварца.
Подключение кварцевого резонатора к stm32
Подключение часового кварцевого резонатора к stm32
Частота кварцевого резонатора для часового кварца составляет 32.768КГц. Емкость конденсаторов обвязки кварца рекомендуется от 5 до 15пФ, подробнее нужно смотреть в документации на используемый резонатор.
В прошивке включение внешнего кварцевого резонатора будет выглядеть следующим образом:
RCC_LSEConfig(RCC_LSE_ON);// Включить тактирование от внешнего часового кварца RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// Выбрать источником тактирования внешний часовой кварц RCC_RTCCLKCmd(ENABLE);// Включить тактирование часовой тактовой шины
Для начала разрешаем работу внешнему часовому кварцу, затем выбираем тактирование часовой шины контроллера от внешнего часового осциллятора, далее включаем саму часовую шину контроллера.
Источник тактирования выбирается командой RTCCLKConfig, с помощью которой можно выбрать следующие источники тактового сигнала:
- RCC_RTCCLKSource_LSE — внешний часовой тактовый резонатор
- RCC_RTCCLKSource_LSI — внутренняя 40КГц LSI RC цепочка
- RCC_RTCCLKSource_HSE_Div128 — тактирование от внешнего основного тактового генератора через 128 кратный предделитель.
Если использовать встроенную 40КГц RC цепочку, то для начала нужно её включить. Настройка в этом случае будет выглядеть следующим образом:
RCC_LSICmd(ENABLE); // Включение тактирования встроенной LSI RC цепочки RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);// Выбрать источником тактирования внутреннюю LSI RC цепочку RCC_RTCCLKCmd(ENABLE); // Включить татикрование часовой тактовой шины
На этом настройка часовой шины контроллера заканчивается, но настройка встроенных часов реального времени ещё нет, она будет описана в следующей статье —
STM32. 7. Встроенные часы реального времени (RTC)
Источник: https://alex-exe.ru/radio/stm32/stm32-oscillator-spl/
Настройка тактового генератора. – ТЕРАВОЛЬТ
В предыдущей статье:
тут
мы смогли создать наш первый проект для STM8L052R8.
мы получили следующий код программы, автоматически сгенерированный ST Visual Develop, вот он:
Код:
stm8/
#include “mapping.inc”
#include “STM8S105C6.inc”; подключим файл STM8S105C6.inc
segment ‘rom’
main.l
; initialize SP
ldw X,#stack_end
ldw SP,X
#ifdef RAM0
; clear RAM0
ram0_start.b EQU $ram0_segment_start
ram0_end.b EQU $ram0_segment_end
ldw X,#ram0_start
clear_ram0.l
clr (X)
incw X
cpw X,#ram0_end
jrule clear_ram0
#endif
#ifdef RAM1
; clear RAM1
ram1_start.w EQU $ram1_segment_start
ram1_end.w EQU $ram1_segment_end
ldw X,#ram1_start
clear_ram1.l
clr (X)
incw X
cpw X,#ram1_end
jrule clear_ram1
#endif
; clear stack
stack_start.w EQU $stack_segment_start
stack_end.w EQU $stack_segment_end
ldw X,#stack_start
clear_stack.l
clr (X)
incw X
cpw X,#stack_end
jrule clear_stack
infinite_loop.l
jra infinite_loop
interrupt NonHandledInterrupt
NonHandledInterrupt.l
iret
segment ‘vectit’
dc.l {$82000000+main} ; reset
dc.l {$82000000+NonHandledInterrupt} ; trap
dc.l {$82000000+NonHandledInterrupt} ; irq0
dc.l {$82000000+NonHandledInterrupt} ; irq1
dc.l {$82000000+NonHandledInterrupt} ; irq2
dc.l {$82000000+NonHandledInterrupt} ; irq3
dc.l {$82000000+NonHandledInterrupt} ; irq4
dc.
l {$82000000+NonHandledInterrupt} ; irq5
dc.l {$82000000+NonHandledInterrupt} ; irq6
dc.l {$82000000+NonHandledInterrupt} ; irq7
dc.l {$82000000+NonHandledInterrupt} ; irq8
dc.l {$82000000+NonHandledInterrupt} ; irq9
dc.l {$82000000+NonHandledInterrupt} ; irq10
dc.l {$82000000+NonHandledInterrupt} ; irq11
dc.l {$82000000+NonHandledInterrupt} ; irq12
dc.
l {$82000000+NonHandledInterrupt} ; irq13
dc.l {$82000000+NonHandledInterrupt} ; irq14
dc.l {$82000000+NonHandledInterrupt} ; irq15
dc.l {$82000000+NonHandledInterrupt} ; irq16
dc.l {$82000000+NonHandledInterrupt} ; irq17
dc.l {$82000000+NonHandledInterrupt} ; irq18
dc.l {$82000000+NonHandledInterrupt} ; irq19
dc.l {$82000000+NonHandledInterrupt} ; irq20
dc.
l {$82000000+NonHandledInterrupt} ; irq21
dc.l {$82000000+NonHandledInterrupt} ; irq22
dc.l {$82000000+NonHandledInterrupt} ; irq23
dc.l {$82000000+NonHandledInterrupt} ; irq24
dc.l {$82000000+NonHandledInterrupt} ; irq25
dc.l {$82000000+NonHandledInterrupt} ; irq26
dc.l {$82000000+NonHandledInterrupt} ; irq27
dc.l {$82000000+NonHandledInterrupt} ; irq28
dc.
l {$82000000+NonHandledInterrupt} ; irq29
end
добавим в него следующие настройки:
(обратите внимание!: в файлах asm и inc определены только названия регистров, название конкретных битов в данных регистров не определены! а это значит, что для удобства будем использовать #define в соответствии с документацией на конкретный микроконтроллер, так будет проще.)
определим биты:
Код:
#define hseen #0; присвоим названию бита hseen значение #0
#define swen #1; присвоим названию бита swen значение #1
#define clock #$B4; тактирование от генератора
#define cssen #0; присвоим названию бита cssen значение #0
инициализируем CLK
Код:
bset CLK_ECKR, hseen; включить внешний кварц
bset CLK_SWCR, swen; разрешаем переключение генераторов
ld A, clock; загрузим значение clock в аккумулятор
ld CLK_SWR, A; выбираем clock от кварцевого генератора (HSE)
ld A, #$0; загрузим значение 0 в аккумулятор
ld CLK_CKDIVR, A; делители частоты внутреннего и внешнего генератора на 1 – частота ядра максимальная
.clocks ; ждем стабилизации частоты
ld A, CLK_CMSR
cp A, #$B4; сравниваем, пока не #$B4
jrne clocks; пока не #$B4 – циклимся на .clocks
bset CLK_CSSR, cssen; разрешаем автопереключение источника Clock при неисправности генератора на внутренний генератор
обратите внимание на адрес метки, .clocks – начинается с точки и прижат к левому краю строку! если сдвинуть – выдаст ошибку при компиляции!
итого получили код программы с настроенным внешним тактовым генератором:
Код:
stm8/
#include “mapping.inc”
#include “STM8S105C6.inc”
#define hseen #0; присвоим названию бита hseen значение #0
#define swen #1; присвоим названию бита swen значение #1
#define clock #$B4; тактирование от генератора
#define cssen #0; присвоим названию бита cssen значение #0
segment ‘rom’
main.l
; initialize SP
ldw X,#stack_end
ldw SP,X
bset CLK_ECKR, hseen; включить внешний кварц
bset CLK_SWCR, swen; разрешаем переключение генераторов
ld A, clock; загрузим значение clock в аккумулятор
ld CLK_SWR, A; выбираем clock от кварцевого генератора (HSE)
ld A, #$0; загрузим значение 0 в аккумулятор
ld CLK_CKDIVR, A; делители частоты внутреннего и внешнего генератора на 1 – частота ядра максимальная
.clocks ; ждем стабилизации частоты
ld A, CLK_CMSR
cp A, #$B4; сравниваем, пока не #$B4
jrne clocks; пока не #$B4 – циклимся на .clocks
bset CLK_CSSR, cssen; разрешаем автопереключение источника Clock при неисправности генератора на внутренний генератор
#ifdef RAM0
; clear RAM0
ram0_start.b EQU $ram0_segment_start
ram0_end.b EQU $ram0_segment_end
ldw X,#ram0_start
clear_ram0.l
clr (X)
incw X
cpw X,#ram0_end
jrule clear_ram0
#endif
#ifdef RAM1
; clear RAM1
ram1_start.w EQU $ram1_segment_start
ram1_end.w EQU $ram1_segment_end
ldw X,#ram1_start
clear_ram1.l
clr (X)
incw X
cpw X,#ram1_end
jrule clear_ram1
#endif
; clear stack
stack_start.w EQU $stack_segment_start
stack_end.w EQU $stack_segment_end
ldw X,#stack_start
clear_stack.l
clr (X)
incw X
cpw X,#stack_end
jrule clear_stack
infinite_loop.l
jra infinite_loop
interrupt NonHandledInterrupt
NonHandledInterrupt.l
iret
segment ‘vectit’
dc.l {$82000000+main} ; reset
dc.l {$82000000+NonHandledInterrupt} ; trap
dc.l {$82000000+NonHandledInterrupt} ; irq0
dc.l {$82000000+NonHandledInterrupt} ; irq1
dc.l {$82000000+NonHandledInterrupt} ; irq2
dc.l {$82000000+NonHandledInterrupt} ; irq3
dc.l {$82000000+NonHandledInterrupt} ; irq4
dc.
l {$82000000+NonHandledInterrupt} ; irq5
dc.l {$82000000+NonHandledInterrupt} ; irq6
dc.l {$82000000+NonHandledInterrupt} ; irq7
dc.l {$82000000+NonHandledInterrupt} ; irq8
dc.l {$82000000+NonHandledInterrupt} ; irq9
dc.l {$82000000+NonHandledInterrupt} ; irq10
dc.l {$82000000+NonHandledInterrupt} ; irq11
dc.l {$82000000+NonHandledInterrupt} ; irq12
dc.
l {$82000000+NonHandledInterrupt} ; irq13
dc.l {$82000000+NonHandledInterrupt} ; irq14
dc.l {$82000000+NonHandledInterrupt} ; irq15
dc.l {$82000000+NonHandledInterrupt} ; irq16
dc.l {$82000000+NonHandledInterrupt} ; irq17
dc.l {$82000000+NonHandledInterrupt} ; irq18
dc.l {$82000000+NonHandledInterrupt} ; irq19
dc.l {$82000000+NonHandledInterrupt} ; irq20
dc.
l {$82000000+NonHandledInterrupt} ; irq21
dc.l {$82000000+NonHandledInterrupt} ; irq22
dc.l {$82000000+NonHandledInterrupt} ; irq23
dc.l {$82000000+NonHandledInterrupt} ; irq24
dc.l {$82000000+NonHandledInterrupt} ; irq25
dc.l {$82000000+NonHandledInterrupt} ; irq26
dc.l {$82000000+NonHandledInterrupt} ; irq27
dc.l {$82000000+NonHandledInterrupt} ; irq28
dc.
l {$82000000+NonHandledInterrupt} ; irq29
end
не забываем комментировать каждую написанную строку, в дальнейшем Вы скажете себе за это спасибо!
пробуем скомпилировать: >>Build F7>>
уверен выдаст 0 ошибок и 0 замечаний, с чем Вас и поздравляю! все по прежнему работает, НО только теперь изменился тактовый генератор, был внутренний, стал внешний, и в случае его неисправности, например при воздействии сильных электромагнитных полей внешний кварцевый генератор может остановиться, микроконтроллер автоматически переведет тактирование на внутренний тактовый генератор и установит необходимый флаг о данном событии, что в дальнейшем можно использовать для поддержания работы, сигнализации о неисправности и т.п., но что Важно контроллер не повиснет а продолжит работать, пусть с другой скоростью, но продолжит, а значит сможет сообщить об ошибке и избежать аварийной ситуации!
Источник: http://TeraVolt.ru/assembler/assembler-dlya-stm8-2/nastroyka-taktovogo-generatora/
Спасибо за чтение!