Artery AT32F403A. Знакомство новичка
Пишу первый раз для аудитории, поэтому представлюсь. Зовут меня Артём, я разработчик приложения
VestaXR для автомобилей LADA. Это приложение является бортовым компьютером для машин с магнитолами (ГУ) на базе Андроид, которое взаимодействует с машиной через электронную плату (канбас), и отправляет сигналы с каншины в ГУ и обратно, позволяя получать все данные и управлять некоторыми настройками автомобиля. Изначально канбас строился на базе STM32F405. Но настали времена, когда этот микроконтроллер стал дорогой и попал под санкции. И вот волею судеб мне пришлось на время переквалифицироваться из программиста приложения для Андроид в программиста микроконтроллера (МК). Работать пришлось с МК, информации о котором очень мало, можно сказать даже что её толком нет. Всё что у меня было, это сайт производителя и один пример с led на github. Речь идёт о МК Artery AT32F403A.
По спецификации это очень навороченный МК

Опыт работы с STM32F405 у меня уже был, я правил уже готовую прошивку. Поэтому знаком с оболочкой Keil и принципами работы. Но я понимал, что здесь всё другое. Кроме конечно языка программирования. Итак, две недели мозгового штурма, поиска информации и тупого копирования кода, принесли свои результаты. Я получил действующий канбас со всеми функциями, которые у него должны быть. работа с USB, CAN и USART. И я хочу с вами поделиться своим опытом, надеюсь кому-то это сэкономит время. Всё по порядку. Моя первая статья будет о самом простом. Таймеры и LED. Так сказать, "hello world" Знакомимся с документами, выложенных на сайте производителя
https://www.arterytek.com/en/product/AT32F403A.jsp
Для работы нам понадобится скачать следующие файлы (архив скачанных файлов в конце статьи): • AT32F403A_407_Firmware_Library_V2.1.4 - примеры и основные шаблоны • Keil5_AT32MCU_AddOn_V2.1.9 - файл данных для Keil и других средств разработки • AT_Link_20221221 - драйвера для программатора Далее тестовая плата (у меня готовый канбас, с перепаянным МК. Стоял STM32F405, поставили AT32F403A. Разводку платы не пришлось менять. Жирный плюс!)

CanbusXR

Итак, запускаем Keil. Нажимаем Pack installer. Далее Import Packs, находим расположение папки Keil5_AT32MCU_AddOn_V2.1.9. Выбираем наш МК и нажимаем "Открыть". В итоге получаем такую картинку:

Открываем папку с примерами AT32F403A_407_Firmware_Library_V2.1.4\project\at_start_f403a\examples\tmr (это примеры таймеров). Находим папку timer_base. Как следует из названия, это базовый пример работы таймера. Открываем проект из папки mdk_v5. Всё стандартно и знакомо, не правда ли? Надо сказать спасибо, все примеры лежат по полочкам. Но осторожно, эти примеры для тестовой доски от Artery. В моём случае у меня уже есть плата.

Что же у нас есть в файле main.c:
• void clkout_config - функция настройки внешнего генератора частоты
• void TMR1_OVF_TMR10_IRQHandler - функция обработки таймера
• main - главное тело программы, которое состоит:
1. system_clock_config() - настройка тактирования всей платы. Не трогаем! К этому мы вернемся ещё в следующих постах
2. at32_board_init(); - настройка отладочной платы. Нам она не нужна, поэтому закомментируем
3. /* get system clock */ crm_clocks_freq_get(&crm_clocks_freq_struct);
- как следует из комментариев, настройка системных часов
4. /* turn led2/led3/led4 on */
at32_led_on(LED2);
at32_led_on(LED3);
at32_led_on(LED4); - включение led на плате. У нас их нет, закомментируем
всё
5. /* enable tmr1 clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
/* tmr1 configuration / / time base configuration / / systemclock/24000/10000 =
1hz */
tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
/* tmr1 overflow interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
/* enable tmr1 */
tmr_counter_enable(TMR1, TRUE); - здесь собственно и объявляется работа
таймера
6. clkout_config() - настройка внешнего генератора частоты
Находим строчку tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1). Здесь мы задаём время работы таймера. Формула такая: время_сек * 10000 - 1. То есть 9999 это 1 секунда, 999 это 100 мс, 29999 - 3 секунды. Обращаем внимание на надпись TMR1. Нажимаем F7, проект компилируется и нам теперь доступны переходы по телу проекта. Переходим по TMR1 и видим, что у нас можно сделать 14 таймеров:

Прекрасно, не правда ли?
Итак, добавляем в теле главной функции main строчки с TMR2.
/* enable tmr1 tmr2 clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
/* tmr1 tmr2 configuration */
/* time base configuration */
/* systemclock/24000/10000 = 1hz */
tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
tmr_base_init(TMR2, 29999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
tmr_interrupt_enable(TMR2, TMR_OVF_INT, TRUE);
/* tmr1 overflow interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
/* enable tmr1 tmr2 */
tmr_counter_enable(TMR1, TRUE);
tmr_counter_enable(TMR2, TRUE);
Строчка 19 - это объявление главной функции работы с таймерами. Она не меняется. Ищем эту функцию и тоже исправляем для TMR2:
void TMR1_OVF_TMR10_IRQHandler(void)
{
if(tmr_flag_get(TMR1, TMR_OVF_FLAG) != RESET)
{
/* add user code... */
//at32_led_toggle(LED3);
tmr_flag_clear(TMR1, TMR_OVF_FLAG);
}
if(tmr_flag_get(TMR2, TMR_OVF_FLAG) != RESET)
{
/* add user code... */
//at32_led_toggle(LED3);
tmr_flag_clear(TMR2, TMR_OVF_FLAG);
}
}
У нас получается что при срабатывании таймера флаг переходит в !reset, с выполняется код в скобках для каждого таймера отдельно. Теперь что касается внешнего генератора, а так же объявления в коде пинов МК. У Artery объявление пинов обозначается gpio_init_struct.gpio_pins = GPIO_PINS_8, без указания A, B, C, D, F, E. (зависит от количество ножек МК). Они указываются в двух строчках:
/* enable gpio port clock */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); // - это его регистр, А
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
/* clkout gpio init */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_14; // - это пин МК
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOA, &gpio_init_struct); // - это его регистр, А
То есть у меня на плате внешний генератор подцеплен на PA14. Если у вас на другой ноге, то и меняете в трёх местах: GPIOA, GPIOB, GPIOC и так далее. С кодом разобрались, теперь надо настроить программатор для режима Debug. переходим в Options for Target, и выбираем CMSIS-DAP. Нажимаем далее Settings. Выбираем программатор.
Нажимаем F7, компилируем, и нажимаем меню Debug - start/stop debug session, и через 5 секунд снова нажимаем F5 для запуска. На плате тишина. Давайте проверим что таймеры работают. Поставим breakpoint на строчку первого таймера
Выйдем из режима debug и добавим функцию инициализации led и впишем её запуск в main
void init_led(void) {
gpio_init_type GPIO_Init;
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); // - очень важно не пропустить
GPIO_Init.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_1;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
GPIO_Init.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_Init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_2;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
}
LED у меня подключены на PC1 и PC2. Для их включения или выключения есть уже готовые функции
at32_led_off(LED3);
at32_led_on(LED2);
Нажимаем F12 на LED3 и переходим в код настройки обозначений

У меня 2 led, поэтому LED_NUM = 2
Нажимаем F12 на at32_led_off в теле main и переходим на эту функцию, прокручиваем код вверх и меняем (создаём) текcт объявления переменных LED, убираем лишнее
Пишем вызов функций включения led в теле main:
at32_led_on(LED3);
at32_led_on(LED2);
Нажимаем F7, далее Debug и у нас загораются оба led. УРА! Поздравляю.Теперь модифицируем функцию обработки таймеров:
void TMR1_OVF_TMR10_IRQHandler(void) {
if(tmr_flag_get(TMR1, TMR_OVF_FLAG) != RESET) {
/* add user code... */
at32_led_toggle(LED3);
tmr_flag_clear(TMR1, TMR_OVF_FLAG);
}
if(tmr_flag_get(TMR2, TMR_OVF_FLAG) != RESET) {
/* add user code... */
at32_led_toggle(LED2);
tmr_flag_clear(TMR2, TMR_OVF_FLAG);
}
}
И снова запускаем. Теперь led у нас перемигиваются. Один с частотой 1 секунда, второй с частотой 3 секунды. Полный код main.с выглядит так:
#include "at32f403a_407_board.h"
#include "at32f403a_407_clock.h"
/** @addtogroup AT32F403A_periph_examples
* @{
*/
/** @addtogroup 403A_TMR_timer_base TMR_timer_base
* @{
*/
crm_clocks_freq_type crm_clocks_freq_struct = {0};
void clkout_config(void) {
gpio_init_type gpio_init_struct;
/* enable gpio port clock */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
/* clkout gpio init */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_14;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOA, &gpio_init_struct);
/* config clkout division */
crm_clkout_div_set(CRM_CLKOUT_DIV_1);
/* config clkout clock */
crm_clock_out_set(CRM_CLKOUT_PLL_DIV_4);
}
/**
* @brief this function handles timer1 overflow handler.
* @param none
* @retval none
*/
void TMR1_OVF_TMR10_IRQHandler(void) {
if(tmr_flag_get(TMR1, TMR_OVF_FLAG) != RESET) {
/* add user code... */
at32_led_toggle(LED3);
tmr_flag_clear(TMR1, TMR_OVF_FLAG);
}
if(tmr_flag_get(TMR2, TMR_OVF_FLAG) != RESET) {
/* add user code... */
at32_led_toggle(LED2);
tmr_flag_clear(TMR2, TMR_OVF_FLAG);
}
}
void init_led(void) {
gpio_init_type GPIO_Init;
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
GPIO_Init.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_Init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_1;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
GPIO_Init.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_Init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_2;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
}
/**
* @brief main function.
* @param none
* @retval none
*/
int main(void) {
system_clock_config();
//at32_board_init();
/* get system clock */
crm_clocks_freq_get(&crm_clocks_freq_struct);
/* turn led2/led3/led4 on */
//at32_led_on(LED2);
//at32_led_on(LED3);
//at32_led_on(LED4);
/* enable tmr1 tmr2 clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
/* tmr1 tmr2 configuration */
/* time base configuration */
/* systemclock/24000/10000 = 1hz */
tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
tmr_base_init(TMR2, 29999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
tmr_interrupt_enable(TMR2, TMR_OVF_INT, TRUE);
/* tmr1 overflow interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
/* enable tmr1 tmr2 */
tmr_counter_enable(TMR1, TRUE);
tmr_counter_enable(TMR2, TRUE);
clkout_config();
// enable led
init_led();
at32_led_on(LED3);
at32_led_on(LED2);
while(1) {
}
}
Ещё один плюс, это очень много комментариев по всем функциям, что облегчает задачу. В принципе на этом первоначальное знакомство можно считать законченным.
Artery AT32F403A. Работа с USB
Итак, продолжаю Вас знакомить с микроконтроллером (МК) AT32F403A. Пожалуй, не ошибусь, если скажу, что работа с USB является, пожалуй, одной из основной. Без этого практически никуда. Дополнительно нам понадобится приложение терминал для Windows. Я использую COM port Terminal v.1.5 Sviridov.
Немного отвлекусь, и скажу с чем мне пришлось столкнуться при разборе примеров работы. Гуру программирования МК посмеются, но я в этом деле новичок, мне можно.
Итак, я запустил пример работы с USB и всё работает. Запустил пример работы с CAN и всё работает. Копирую код с примера CAN в USB — CAN не работает. Копирую код с примера USB в CAN — USB не работает. Чудеса (для меня). Так же по прошлой работе с STM я помнил про настройку тактирования (поправьте если терминология неверная). Пока с ней не столкнулся. Примеры же работают.
Начал пошагово смотреть все строчки в обоих примерах. И нашёл функцию void system_clock_config(void).
CAN работает при частоте: crm_pll_config(CRM_PLL_SOURCE_HEXT_DIV,
CRM_PLL_MULT_60, CRM_PLL_OUTPUT_RANGE_GT72MHZ);
USB работает при частоте: crm_pll_config(CRM_PLL_SOURCE_HEXT_DIV,
CRM_PLL_MULT_48, CRM_PLL_OUTPUT_RANGE_GT72MHZ);
Значит пора искать, где это у китайцев настраивается. Есть отдельное приложение AT32_New_Clock_Configuration_V3.0.05. Оно есть на сайте artery, есть в архиве первого поста. Запускаем приложение. Выбираем Project — New — AT32F403A.
Из документации китайцев я прочитал, что частота, на которой работает USB, должна быть отделена от общей. И работа USB должна быть на частоте 48Мгц. Это, кстати, следует из названия функции в примере. Чуть ниже увидите.

Меняем настройки
Нажимаем Generate Code, нам предлагают выбрать папку, куда сохранить файлы. Создаём папку CLK AT32F403A и нажимаем сохранить. В папке появляются две подпапки src и inc. Всё, можно приступать к изучению.
Находим пример работы с USB. Это папка AT32F403A_407_Firmware_Library_V2.1.4\project\at_start_f403a\examples\usb_devic e\virtual_comport
Копируем полученные ранее файлы: из папки CLK AT32F403A\src - только один файл at32f403a_407_clock в папку virtual_comport\src с заменой. Из папки CLK AT32F403A\inc - оба файла, at32f403a_407_clock.h и at32f403a_407_conf.h в папку virtual_comport\inc с заменой.
Запускаем пример из папки virtual_comport\mdk_v5. Компилируем проект F7. Открываем main.c. И не пугаемся, код уже намного больше, чем в прошлом примере. Находим main функцию. Всю функцию приводить не буду, только код инициализации.
/* config nvic priority group */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
// at32_board_init(); - убираем
/* usart gpio config */
// usart_gpio_config(); - нам не требуется, убираем
/* hardware usart config: usart2 */
// usb_usart_config(linecoding); - нам не требуется, убираем
/* select usb 48m clcok source */ - Как я говорил ранее, 48Мгц частота работы USB
// usb_clock48m_select(USB_CLK_HEXT); - нам не требуется, убираем, мы уже настроили выше частоту
/* enable usb clock */
crm_periph_clock_enable(CRM_USB_PERIPH_CLOCK, TRUE);
/* enable usb interrupt */
nvic_irq_enable(USBFS_L_CAN1_RX0_IRQn, 0, 0);
/* usb core init */
usbd_core_init(&usb_core_dev, USB, &cdc_class_handler, &cdc_desc_handler, 0);
/* enable usb pull-up */
usbd_connect(&usb_core_dev);
USB у нас подцеплен на PA11 и PA12.
Вроде всё, компилируем F7 и запускаем режим Debug и нажимаем F5. (Без режима Debug? простым F8 не заработало. Может у меня что-то не так). Если всё удачно, с компьютера услышите звук подключенного usb устройства. Заходим в терминал и нажимаем Поиск.
Добавим таймеры и LED в наш проект, из первой статьи. И делаем два таймера, на 500 мс и 1 секунду (1999 и 3999. Эти числа рассчитаны на основе системной частоты, которую мы поменяли выше, поэтому отличается от первого поста).
// таймеры
/* enable tmr1 tmr2 clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
/* tmr1 tmr2 configuration */
/* time base configuration */
/* systemclock/24000/10000 = 1hz */
tmr_base_init(TMR1, 1999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
tmr_base_init(TMR2, 3999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
tmr_interrupt_enable(TMR2, TMR_OVF_INT, TRUE);
/* tmr1 overflow interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
/* enable tmr1 tmr2 */
tmr_counter_enable(TMR1, TRUE);
tmr_counter_enable(TMR2, TRUE);
// LED
init_led();
at32_led_off(LED3); // гасим зелёный
at32_led_on(LED2); // зажигаем красный, типа устройство включено
Сделаем индикацию USB соединения. Объявляем переменную uint8_t usb_ready = 0. Меняем код прерывания USB:
void USBFS_L_CAN1_RX0_IRQHandler(void)
{
usbd_irq_handler(&usb_core_dev);
usb_ready = 1;
}
В коде таймера пишем:
if(tmr_flag_get(TMR1, TMR_OVF_FLAG) != RESET) {
if (usb_ready == 1) {
at32_led_on(LED2);
} else {
at32_led_toggle(LED2);
}
usb_ready = 0;
tmr_flag_clear(TMR1, TMR_OVF_FLAG);
}
На выходе получаем: есть связь, красный диод горит, выдёргиваем usb из разъёма, красный диод начинает мигать с частотой 500 мс.
Теперь самое интересное, обмен информацией. Сделаем отправку в терминал серийного номера процессора AT32.
Для этого добавим переменные:
• uint32_t cortex_id, cortex_id_2, cortex_id_3;
• uint8_t ButtonTx_Buffer_usb[10] = {0x0A, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00};
Так же добавим для новых функций строку в начале кода #include <string.h>.
В коде таймера пишем:
if(tmr_flag_get(TMR2, TMR_OVF_FLAG) != RESET) {
cortex_id = *(uint32_t *)0x1FFFF7E8; // получаем 1 часть серийного номера МК
cortex_id_2 = *(uint32_t *)0x1FFFF7EC; // получаем 2 часть серийного номера МК
cortex_id_3 = *(uint32_t *)0x1FFFF7F0; // получаем 3 часть серийного номера МК
memcpy(&ButtonTx_Buffer_usb[2], (uint32_t*)&cortex_id_3, 4);
memcpy(&ButtonTx_Buffer_usb[6], (uint32_t*)&cortex_id_2, 4);
usb_vcp_send_data(&usb_core_dev, ButtonTx_Buffer_usb, 0x000A); // эта функция
отвечает за отправку данных в usb
// 0x000A - это длина пакета, в моём случае 10 байт
at32_led_toggle(LED3); // весело мигаем зелёным диодом
tmr_flag_clear(TMR2, TMR_OVF_FLAG);
}
Обратите внимание, я беру только 2 и 3 часть серийного номера. Я проверял, у МК меняется только 3 часть номера. То есть особо смысла использовать 1 и 2 часть номера нет.
Отлично. Теперь научимся принимать данные с терминала. Открываем функцию main и смотрим что у нас в теле while. Всё оттуда удаляем, и оставляем только следующий код:
while(1) {
data_len = usb_vcp_get_rxdata(&usb_core_dev, usb_buffer);
if(data_len > 0) {
work_with_mmc();
}
}
Здесь просто, если пришёл пакет, data_len становится отличной от 0 и мы переходим в функцию work_with_mmc(). Напишем теперь эту функцию.
Объявляем переменные:
• uint8_t USB_CRC = 0;
• uint8_t receivedUSBData[13] = {0};
// Для примера я шлю из терминала строку HEX $AA$E0$07$08$03$19$02$AF$00$00$00$00$99
void work_with_mmc(void) {
uint8_t i2;
memcpy(receivedUSBData, usb_buffer, data_len); // копируем принятый пакет из usb_buffer в receivedUSBData в количестве data_len
if (data_len == 13) { // проверяем пакет на длину
if (receivedUSBData[0] == 0xAA) { // если нулевой байт равен AA, то продолжаем
USB_CRC = 0;
for (i2 = 0; i2 < 12; i2++) {
USB_CRC = USB_CRC + receivedUSBData[i2];
}
if (0xFF-USB_CRC == receivedUSBData[12]) { // проверяем CRC
// отправляем полученный пакет обратно в USB
memcpy(&ButtonTx_Buffer_usb[0], (uint8_t*)&receivedUSBData[3], 10);
usb_vcp_send_data(&usb_core_dev, ButtonTx_Buffer_usb, 0x000A);
}
}
}
}
Как видите, всё достаточно просто. Меняя нулевой байт пакета, мы можем сделать много управляющих пакетов для работы МК. Я в частности меняю из магнитолы режимы работы прошивки, под разные настройки.
Artery AT32F403A. Работа с CAN
1. Знакомство с таймерами и LED
2. Работа с USB
Сегодня я познакомлю Вас с работой МК с CAN шиной. В автомобиле, да и не только, без неё никуда. Пример мы сделаем на основе прошлого примера работы с USB. То есть соединим пример работы с USB и с CAN. Дополнительно нам понадобится канхакер, и приложение для работы с ним, например CarBUSAnalyzer.
