Семейство микроконтроллеров tinyAVR® компании Microchip с независимыми от ядра периферийными устройствами (CIP), высокоскоростными внутренними генераторами и системами событий пользуется широкой популярностью. Недавно выпущенная Microchip серия микроконтроллеров megaAVR® — ATmega4809 имеет большую емкость памяти и больше выводов и является расширением серии tinyAVR. Новая серия ATmega4809 является идеальным вспомогательным микроконтроллером для сложных систем, использующих микропроцессоры, и может стать отличным автономным процессором в конструкциях систем управления.
Особенности ATmega4809
ATmega4809 — первое устройство megaAVR, в котором интегрированы периферийные устройства, независимые от ядра (CIP), что позволяет выполнять задачи на аппаратном уровне, а не на программном. Оно также расширяет возможности систем управления в реальном времени за счет сочетания интеллектуальных аппаратных периферийных устройств с функциями низкого энергопотребления ядра AVR®.
- 8-разрядный процессор AVR® с аппаратным умножителем
- Флэш-память до 48 КБ
- До 16 каналов высокоскоростного 10-разрядного АЦП
- Настраиваемые пользовательские логические периферийные устройства
- Встроенный высокоскоростной аналого-цифровой преобразователь (АЦП)
Эти характеристики делают новую серию микроконтроллеров megaAVR идеальным выбором для использования в качестве сопутствующих микроконтроллеров в системах на базе микропроцессоров или в качестве автономного процессора в системах управления и контроля.
Схема ATmega4809 Curiosity Nano

Код запуска ATmega4809
Необходимые инструменты
- Аппаратное обеспечение: плата разработчика ATmega4809 Curiosity Nano
- Программное обеспечение: MPLAB X IDE v5.5, компилятор XC8
Настройки параметров компиляции
По умолчанию в MPLAB используется стандартный стартовый код (встроенный в MicroChip). Если вы хотите использовать в своем проекте самодельный стартовый код, вам необходимо установить следующие параметры компиляции:

Выберите проект и откройте панель свойств проекта. Добавьте опцию «-nostartfiles» в разделе «Дополнительные опции» и сохраните изменения.
Обработка функций прерываний микроконтроллера
Когда нет оператора перехода, код выполняется по порядку с самого начала. При возникновении прерывания программа автоматически переходит к соответствующему адресу входа прерывания, который является непрерывным адресом. Обычно такой непрерывный адрес входа прерывания называется таблицей векторов прерываний. Поскольку объем памяти, соответствующий адресу входа прерывания, составляет всего 16 бит (2 байта), в этом пространстве невозможно сохранить код нашей функции обслуживания прерываний. Поэтому мы поместим оператор перехода в адрес входа прерывания, чтобы перейти к адресу входа нашей функции обслуживания прерываний и выполнить нашу функцию обслуживания прерываний.
Стартовый код - версия сборки
/* This file uses not the AVRASM2.exe assembler but the gnu assembler as - the GNU assembler */
/* Replace the rjmp command with jmp */
#include
.extern main; refers to the main function in the Main.c file
/* Interrupt vector table. Place jump instructions. When an interrupt occurs, jump to the corresponding interrupt service function to execute the interrupt function */
.section .vectors
jmp __ctors_end;
jmp CRCSCAN_NMI
jmp BOD_VLM
jmp RTC_CNT_MEGA4809
jmp RTC_PIT
jmp CCL_CCL
jmpPORTA_PORT
jmp TCA0_OVF_vect
/* Code storage area that runs before the main function is run */
.section .init2
clr r1; Clear r1 register. Some compilers require this
clr r16; Clear SREG status register
out SREG, r16
; Init the STACK Pointer. Initialization stack. Used for calling sub-functions
ldi r16,(RAMEND & 0xff); initialize
out CPU_SPL,r16; stack pointer.
ldi r16,(RAMEND >> 8) ; to RAMEND
out CPU_SPH,r16
.section .init9
rcall main ; jump to main function
jmp 0x00; Function executed after the main function ends. Jump directly to 0x00 to reset the MCU
// code space
.section .text
//interrupt service function
.weak CRCSCAN_NMI; Use the .weak directive to define the function. When this function is defined externally, the externally defined function is used
.globalCRCSCAN_NMI
CRCSCAN_NMI:
reti
.weak BOD_VLM
.global BOD_VLM
BOD_VLM:
reti
.weak RTC_CNT_MEGA4809
.global RTC_CNT_MEGA4809
RTC_CNT_MEGA4809:
reti
.weak RTC_PIT
.globalRTC_PIT
RTC_PIT:
reti
.weak CCL_CCL
.global CCL_CCL
CCL_CCL:
reti
.weakPORTA_PORT
.globalPORTA_PORT
PORTA_PORT:
reti
.end
Тестовый код
Скомпилируйте тестовый код этого файла запуска в основной функции, чтобы определить, может ли написанный нами запуск войти в прерывание переполнения TCA0.
#include "mcc_generated_files/mcc.h"
volatile uint8_t flag = 0;
int main(void)
{
/* Initializes MCU, drivers and middleware */
SYSTEM_Initialize();
/* Replace with your application code */
// protected_write_io(&(CLKCTRL.MCLKCTRLB),IO_KEY,0x01);
PORTF.DIR = 0x20;
TCA0.SINGLE.PERH = 0x4C;
TCA0.SINGLE.PERL = 0x4B;
TCA0.SINGLE.CTRLA = 0x0D;
TCA0.SINGLE.INTCTRL = 0x01;
ENABLE_INTERRUPTS();
while(1)
{
if(flag==1)
{
flag = 0;
PORTF.OUTTGL = 0x20;
}
}
}
ISR(TCA0_OVF_vect)
{
flag = 1;
TCA0.SINGLE.INTFLAGS = 0x01;//??????
}
Корпус для разработки ATmega4809 — выход GPIO
Необходимые инструменты
- Аппаратное обеспечение: плата разработчика ATmega4809 Curiosity Nano
- Программное обеспечение: Microchip Studio 7
Создать новый проект
Создайте новый проект в Microchip Studio 7 и добавьте в него новую папку.
Выберите проект, щелкните правой кнопкой мыши и выберите «Добавить» >> «Новая папка».

Добавьте файлы в папку, выберите файл C и введите имя файла C VPORT.c.

Следуйте тому же методу, чтобы создать новый файл VPORT.h.
Установите путь к файлу заголовка
Откройте окно настроек проекта, щелкните настройки проекта, чтобы установить путь к файлу заголовка:

Напишите код
Мы используем структуры для управления периферийными устройствами. Поскольку адрес памяти, занимаемый структурой, является непрерывным, как и массив, и при проверке руководства по микросхеме мы также обнаружим, что адрес группы регистров периферийных устройств VPORTF также подключен. Таким образом, мы можем назначить базовый адрес регистра VPORF указателю структуры.
typedef struct VPin_x_Jack{
uint8_t PIT_0: 1;
uint8_t PIN_1: 1;
uint8_t PIN_2: 1;
uint8_t PIN_3: 1;
uint8_t PIN_4: 1;
uint8_t PIN_5: 1;
uint8_t PIN_6: 1;
uint8_t PIN_7: 1;
}VPINx_Jack_TypeDef;
typedef struct VPort_x_Jack{
VPINx_Jack_TypeDef DIR;
VPINx_Jack_TypeDef OUT;
VPINx_Jack_TypeDef IN;
VPINx_Jack_TypeDef INTFLAGS;
}VPORTx_Jack_TypeDef;
#define VPORTA_Jack (*(VPORTx_Jack_TypeDef *)0x0000)
#define VPORTB_Jack (*(VPORTx_Jack_TypeDef *)0x0004)
#define VPORTC_Jack (*(VPORTx_Jack_TypeDef *)0x0008)
#define VPORTD_Jack (*(VPORTx_Jack_TypeDef *)0x000C)
#define VPORTE_Jack (*(VPORTx_Jack_TypeDef *)0x0010)
#define VPORTF_Jack (*(VPORTx_Jack_TypeDef *)0x0014)
Закрепить заголовочный файл в файле main.c
#include
#include "VPORTx.h"
extern protected_write_io(void *addr, uint8_t KEY,uint8_t value);
static inline void System_Clock_Setting(void *addr,uint8_t value)
{
protected_write_io(addr,0xD8,value);
}
void LED_Init(void)
{
VPORTF_Jack.DIR.PIN_5 = 1; // PF5 output
VPORTF_Jack.OUT.PIN_5 = 1; // LED off
}
int main(void)
{
//Configure the system clock to 10MHZ
System_Clock_Setting((void *)&(CLKCTRL.MCLKCTRLB),CLKCTRL_PDIV_2X_gc | 1 << CLKCTRL_PEN_bp);
//Initialize LED port
LED_Init();
while (1)
{
}
}
Код управления светодиодной подсветкой:
Проверьте схему, чтобы убедиться, что порт ввода-вывода, подключенный к выводу светодиода, является PF5. Поскольку положительный вывод светодиода подключен к источнику питания, когда отрицательный вывод светодиода находится в низком состоянии, светодиод горит. В противном случае светодиод гаснет.
VPORTF_Jack.OUT.PIN_5 = 1; // LED off
VPORTF_Jack.OUT.PIN_5 = 0; // LED is on
Отладка кода
Как показано на рисунке ниже, настройте проект как Simulator и используйте отладчик симуляции для отладки кода.

Откройте окно «I/O View» (Просмотр ввода-вывода), чтобы просмотреть состояние регистра выводов.





