Третий пример от Грока:
memento mori
Для реализации вашей задачи, где данные с АЦП собираются по таймеру, заносятся в массив CAN-сообщения в том же обработчике таймера, а отправка происходит только в ответ на запрос по CAN, можно использовать следующий подход. Данные будут обновляться периодически в обработчике прерывания таймера, а отправка — инициироваться в обработчике прерывания CAN при получении запроса. Вот пример реализации для микроконтроллера C167 на языке C.
#include <reg167.h>
// Определение констант
#define ADC_CHANNEL 0 // Канал АЦП
#define CAN_ID_REQUEST 0x100 // Идентификатор запроса по CAN
#define CAN_ID_RESPONSE 0x101 // Идентификатор ответа по CAN
// Глобальный массив для хранения данных CAN-сообщения
volatile unsigned char can_data[2];
// Инициализация АЦП
void init_adc() {
ADC_CON = 0x0000; // Сброс настроек АЦП
ADC_CON |= (1 << 5); // Включение АЦП
ADC_CON |= (ADC_CHANNEL & 0x0F); // Выбор канала
}
// Инициализация таймера
void init_timer() {
T2CON = 0x0000; // Сброс таймера 2
T2 = 0; // Начальное значение
T2REL = 1000; // Период таймера (примерный период)
T2CON |= 0x0040; // Запуск таймера
T2IC = 0x0044; // Включение прерывания таймера, приоритет
}
// Инициализация CAN
void init_can() {
CAN_CON = 0x41; // Инициализация CAN-контроллера
// Настройка объекта для приема запросов (объект 0)
CAN_OBJ[0].MCR = 0x5555; // Маска для приема
CAN_OBJ[0].AR = CAN_ID_REQUEST; // Идентификатор запроса
CAN_OBJ[0].MOFCR = 0x0008; // Режим приема
// Настройка объекта для отправки данных (объект 1)
CAN_OBJ[1].AR = CAN_ID_RESPONSE; // Идентификатор ответа
CAN_OBJ[1].MOFCR = 0x0000; // Режим отправки
}
// Обработчик прерывания таймера
void timer_handler() interrupt 0x20 {
unsigned int adc_value = ADC_DAT; // Чтение данных с АЦП
can_data[0] = adc_value & 0xFF; // Младший байт
can_data[1] = (adc_value >> 8) & 0xFF; // Старший байт
}
// Обработчик прерывания CAN
void can_handler() interrupt 0x40 {
if (CAN_OBJ[0].MOFCR & 0x0001) { // Проверка, принято ли сообщение на объекте 0
unsigned char local_data[2];
EA = 0; // Отключение прерываний для безопасного копирования
local_data[0] = can_data[0];
local_data[1] = can_data[1];
EA = 1; // Включение прерываний
// Копирование данных в буфер отправки
CAN_OBJ[1].DATA[0] = local_data[0];
CAN_OBJ[1].DATA[1] = local_data[1];
CAN_OBJ[1].MOFCR |= 0x0001; // Инициирование отправки
}
}
// Основная функция
void main() {
init_adc(); // Инициализация АЦП
init_timer(); // Инициализация таймера
init_can(); // Инициализация CAN
EA = 1; // Включение глобальных прерываний
while (1) {
// Основной цикл свободен для других задач
}
}
- Сбор данных: В обработчике прерывания таймера (timer_handler) данные с АЦП читаются и сразу заносятся в массив can_data. Это происходит с заданной периодичностью, определяемой настройками таймера (T2REL).
- Отправка по запросу: В обработчике прерывания CAN (can_handler) проверяется получение запроса по CAN. Если запрос получен, данные из can_data копируются в буфер отправки и передаются через CAN.
- Синхронизация: Чтобы избежать изменения данных во время копирования, прерывания временно отключаются (EA = 0) на время работы с can_data.
- Период таймера (T2REL = 1000) — это примерное значение. Настройте его под ваши требования (например, в зависимости от частоты опроса АЦП).
- Если данные с АЦП требуют нормирования, добавьте соответствующую функцию в timer_handler перед записью в can_data.
- Код предполагает, что CAN-сообщение содержит 2 байта данных (16-битное значение с АЦП). При необходимости размер массива can_data можно изменить.