Добавлено:
- рефакторинг названий: - маленькие буквы - инит периферии - ТакойСтильФункций - API для использования - сделаны шапки с инструкциями к функциями - доработан ацп секвенсора - доработан систем тики. можно настроить его на разные частоты и подключить коллбеки на разный период - в gpio добавлены функции для кнопок и диодов - генерация бинарника
This commit is contained in:
487
Core/App/adc.c
487
Core/App/adc.c
@@ -1,22 +1,115 @@
|
||||
/*==============================================================================
|
||||
* Инициализация АЦП с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file adc.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер ADC на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию ADC и аналогового модуля (AM)
|
||||
* + Управление секвенсорами (SEQ0, SEQ1):
|
||||
* - Инициализацию и конфигурацию секвенсоров
|
||||
* - Запуск и остановку преобразований с буфером
|
||||
* - Обработку прерываний секвенсоров
|
||||
* - Установку callback-функций для событий:
|
||||
* - завершение секвенсора
|
||||
* - половина буфера
|
||||
* - полный буфер
|
||||
* - ошибка
|
||||
* + Управление цифровыми компараторами (DC0-DC3):
|
||||
* - Инициализацию и конфигурацию компараторов
|
||||
* - Запуск и остановку компараторов
|
||||
* - Обработку прерываний компараторов
|
||||
* - Установку callback-функций для событий:
|
||||
* - срабатывание компаратора
|
||||
* - ошибка
|
||||
* + Функции для работы с каналами ADC
|
||||
* + Программный запуск преобразований
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены конфигурационные структуры adc_seqx_config и adc_dcx_config
|
||||
* в periph_config.h
|
||||
* - Настроено тактирование ADC через RCU
|
||||
* - Для использования прерываний - включены соответствующие NVIC IRQ
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Общие функции ADC:
|
||||
|
||||
a) Инициализация:
|
||||
(+) adc_init_first() — обязательный вызов перед использованием ADC
|
||||
|
||||
b) Работа с каналами:
|
||||
(+) ADC_Get_ChannelValue(&hadc, channel) — получение текущего значения канала
|
||||
|
||||
|
||||
2. Секвенсоры (SEQ):
|
||||
|
||||
a) Настройка периферии (periph_config.h):
|
||||
(+) Определить структуры ADC_SEQ_ExtInit_TypeDef для нужных секвенсоров:
|
||||
adc_seq0_config, adc_seq1_config
|
||||
(+) Настроить последовательность каналов, режимы работы
|
||||
(+) Настроить прерывания (IT) и ITCount
|
||||
(+) Определить callback-функции (можно NULL)
|
||||
|
||||
b) Инициализация:
|
||||
(+) adc_init_first() — первичная настройка тактирования, сброс ADC, инициализация хендла hadc
|
||||
(+) adc_seq_init(&hadc, ADC_SEQ_Num_0, &adc_seq0_config) — инициализация конкретного секвенсора
|
||||
|
||||
c) Callback-функции (опционально):
|
||||
(+) ADC_SEQ_Set_Callback(&hadc, ADC_SEQ_Num_0, ADC_Callback_SeqCplt, Callback) — завершение секвенсора
|
||||
(+) ADC_SEQ_Set_Callback(&hadc, ADC_SEQ_Num_0, ADC_Callback_BuffHalf, Callback) — половина буфера
|
||||
(+) ADC_SEQ_Set_Callback(&hadc, ADC_SEQ_Num_0, ADC_Callback_BuffFull, Callback) — полный буфер
|
||||
(+) ADC_SEQ_Set_Callback(&hadc, ADC_SEQ_Num_0, ADC_Callback_Error, Callback) — ошибки
|
||||
|
||||
d) Запуск и остановка:
|
||||
(+) ADC_SEQ_Start(&hadc, ADC_SEQ_Num_0, data_buffer, buffer_size) — запуск с буфером
|
||||
(+) ADC_SEQ_Stop(&hadc, ADC_SEQ_Num_0) — остановка секвенсора
|
||||
|
||||
e) Работа с данными:
|
||||
(+) ADC_Get_ChannelValue(&hadc, channel) — чтение текущего значения канала из хендла
|
||||
(+) ADC_SEQ_SoftwareStart() — программный запуск преобразования
|
||||
|
||||
f) Обработка прерываний:
|
||||
(+) adc_seq_irq_handler(&hadc, ADC_SEQ_Num_0) — обработчик прерываний секвенсора
|
||||
- В обработчике автоматически читаются данные из FIFO, обновляются каналы и буфер
|
||||
- В обработчиках автоматически вызываются соответствующие callback-функции
|
||||
и сбрасываются флаги
|
||||
|
||||
g) Особенности работы:
|
||||
(+) Данные автоматически читаются из FIFO в прерывании
|
||||
(+) Поддерживается кольцевой буфер (BufferCircular)
|
||||
(+) Автоматический вызов callback при заполнении половины/всего буфера
|
||||
|
||||
3. Цифровые компараторы (DC):
|
||||
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "periph_config.h"
|
||||
|
||||
ADC_HandleTypeDef hadc;
|
||||
ADC_HandleTypeDef hadc; /*!< Хендл ADC */
|
||||
|
||||
//-- Private function prototypes -----------------------------------------------
|
||||
static void __adc_seq_fifo_read(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
static int __adc_seq_calc_fifo_load(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////SEQUENCORS/////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//-- ADC Init functions --------------------------------------------------------
|
||||
/**
|
||||
* @brief Первичная инициализация ADC
|
||||
* @details Настройка ADC и хендла: тактирования, прерывания
|
||||
* и секвенсоры с компараторами
|
||||
*/
|
||||
void adc_init_first(void)
|
||||
{
|
||||
#if (USE_ADC_SEQ0==1) || (USE_ADC_SEQ1==1) || (USE_ADC_DC0==1) || (USE_ADC_DC1==1) || (USE_ADC_DC2==1) || (USE_ADC_DC3==1)
|
||||
@@ -41,11 +134,12 @@ void adc_init_first(void)
|
||||
#endif
|
||||
#if (USE_ADC_SEQ1==1)
|
||||
adc_seq_init(&hadc, ADC_SEQ_Num_1, &adc_seq1_config);
|
||||
if(hadc.SEQ_Config[ADC_SEQ_Num_1]->IT == ENABLE)
|
||||
if(hadc.SEQ[ADC_SEQ_Num_1].Config->IT == ENABLE)
|
||||
{
|
||||
NVIC_EnableIRQ(ADC_SEQ1_IRQn);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (USE_ADC_DC0==1)
|
||||
#endif
|
||||
#if (USE_ADC_DC1==1)
|
||||
@@ -64,6 +158,8 @@ void adc_init_first(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
//-- ADC Sequencers API functions ----------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализация секвенсора АЦП
|
||||
* @param hadc указатель на хендл АЦП
|
||||
@@ -87,6 +183,16 @@ OperationStatus adc_seq_init(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Nu
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
|
||||
if(conf->SEQ_Init.RestartTimer) // не значю почему но этот таймер работает в 2 раза медленее чем AdcClk
|
||||
{
|
||||
conf->SEQ_Init.RestartTimer = (conf->SEQ_Init.RestartTimer+1)/2-1; // поэтому дополнительно делим всё на два чтобы работало
|
||||
}
|
||||
|
||||
if(__adc_seq_calc_fifo_load(hadc, SEQ_Num) < 0)
|
||||
return ERROR;
|
||||
|
||||
|
||||
ADC_SEQ_Init(SEQ_Num, &hseq->Config->SEQ_Init);
|
||||
|
||||
return OK;
|
||||
@@ -95,20 +201,20 @@ OperationStatus adc_seq_init(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Nu
|
||||
/**
|
||||
* @brief Установка коллбека секвенсора АЦП
|
||||
* @param hadc указатель на хендл АЦП
|
||||
* @param cb_type Тип коллбека
|
||||
* @param CallbackType Тип коллбека
|
||||
* @param Callback Функция коллбека
|
||||
* @retval void
|
||||
*/
|
||||
OperationStatus adc_seq_set_callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_CallbackTypeDef cb_type, void (*Callback)(void))
|
||||
OperationStatus ADC_SEQ_Set_Callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_CallbackTypeDef CallbackType, void (*Callback)(void))
|
||||
{
|
||||
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
|
||||
return ERROR;
|
||||
|
||||
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
|
||||
switch(cb_type)
|
||||
switch(CallbackType)
|
||||
{
|
||||
case ADC_Callback_Seq:
|
||||
case ADC_Callback_SeqCplt:
|
||||
hseq->Config->SEQCpltCallback = Callback;
|
||||
break;
|
||||
case ADC_Callback_Error:
|
||||
@@ -135,7 +241,7 @@ OperationStatus adc_seq_set_callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDe
|
||||
* @param buffer_size размер буфера для каждого канала (0 если буфер не используется)
|
||||
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
*/
|
||||
OperationStatus adc_seq_start(ADC_HandleTypeDef *hadc,
|
||||
OperationStatus ADC_SEQ_Start(ADC_HandleTypeDef *hadc,
|
||||
ADC_SEQ_Num_TypeDef SEQ_Num,
|
||||
uint16_t (*data_buffer)[],
|
||||
uint32_t buffer_size)
|
||||
@@ -151,18 +257,24 @@ OperationStatus adc_seq_start(ADC_HandleTypeDef *hadc,
|
||||
hseq->buffer_size = buffer_size;
|
||||
hseq->buffer_count = 0; // Сбрасываем счетчик
|
||||
|
||||
|
||||
// DMA > IT
|
||||
if(conf->SEQ_Init.DMAEn == ENABLE)
|
||||
{
|
||||
conf->IT = DISABLE;
|
||||
}
|
||||
|
||||
// Настраиваем прерывания если нужно
|
||||
if (conf->IT == ENABLE)
|
||||
{
|
||||
ADC_SEQ_ITConfig(SEQ_Num, conf->ITCount, DISABLE);
|
||||
uint32_t it_real_cnt = (uint32_t)(conf->ITCount+1)*(conf->SEQ_Init.ReqMax+1);
|
||||
ADC_SEQ_ITConfig(SEQ_Num, it_real_cnt-1, DISABLE);
|
||||
ADC_SEQ_ITCmd(SEQ_Num, ENABLE);
|
||||
}
|
||||
|
||||
// Включаем секвенсор
|
||||
ADC_SEQ_Cmd(SEQ_Num, ENABLE);
|
||||
|
||||
// Помечаем как запущенный
|
||||
hseq->running = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -174,22 +286,19 @@ OperationStatus adc_seq_start(ADC_HandleTypeDef *hadc,
|
||||
* @param SEQ_Num номер секвенсора
|
||||
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
*/
|
||||
OperationStatus adc_seq_stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
OperationStatus ADC_SEQ_Stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
{
|
||||
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
|
||||
return ERROR;
|
||||
|
||||
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
// ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
|
||||
// Выключаем секвенсор
|
||||
ADC_SEQ_Cmd(SEQ_Num, DISABLE);
|
||||
|
||||
// Выключаем прерывания
|
||||
ADC_SEQ_ITCmd(SEQ_Num, DISABLE);
|
||||
|
||||
// Сбрасываем флаг запуска
|
||||
hseq->running = 1;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -199,40 +308,34 @@ OperationStatus adc_seq_stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Nu
|
||||
* @param channel номер канала
|
||||
* @retval значение ADC (0 если данные невалидны)
|
||||
*/
|
||||
uint16_t adc_get_channel_value(ADC_HandleTypeDef *hadc, ADC_CH_Num_TypeDef channel)
|
||||
uint16_t ADC_Get_ChannelValue(ADC_HandleTypeDef *hadc, ADC_CH_Num_TypeDef channel)
|
||||
{
|
||||
if (!hadc || channel >= ADC_CH_Total)
|
||||
if (!hadc || (int)channel >= ADC_CH_Total)
|
||||
return 0;
|
||||
|
||||
if (hadc->ChannelValid[channel])
|
||||
{
|
||||
return hadc->ChannelData[channel];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return hadc->ChannelData[channel];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Программный запуск преобразования
|
||||
*/
|
||||
void adc_sw_start(void)
|
||||
void ADC_SEQ_SoftwareStart(void)
|
||||
{
|
||||
ADC_SEQ_SwStartCmd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int itcnt;
|
||||
/**
|
||||
* @brief Обработчик прерываний секвенсора
|
||||
* @param hadc указатель на хендл АЦП
|
||||
* @param SEQ_Num номер секвенсора
|
||||
* @retval void
|
||||
*/
|
||||
void adc_seq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
void adc_seq_irq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
{
|
||||
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
|
||||
return;
|
||||
|
||||
// GPIO_SetBits(GPIOA, GPIO_Pin_7);
|
||||
itcnt++;
|
||||
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
|
||||
|
||||
@@ -242,73 +345,7 @@ void adc_seq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
// Очищаем флаг
|
||||
ADC_SEQ_ITStatusClear(SEQ_Num);
|
||||
|
||||
// Последний запрос в секвенсоре
|
||||
ADC_SEQ_ReqNum_TypeDef last_request = conf->SEQ_Init.ReqMax;
|
||||
|
||||
// Читаем все доступные данные из FIFO
|
||||
uint8_t channels_processed = 0;
|
||||
while (ADC_SEQ_GetFIFOLoad(ADC_SEQ_Num_0))
|
||||
{
|
||||
uint32_t data = ADC_SEQ_GetFIFOData(SEQ_Num);
|
||||
ADC_SEQ_ReqNum_TypeDef req_num = ADC_SEQ_GetReqCurrent(SEQ_Num);
|
||||
|
||||
if (req_num < ADC_SEQ_Req_Total)
|
||||
{
|
||||
ADC_CH_Num_TypeDef channel = conf->SEQ_Init.Req[req_num];
|
||||
|
||||
if (channel < ADC_CH_Total)
|
||||
{
|
||||
// 1. Обновляем текущее значение
|
||||
hadc->ChannelData[channel] = (uint16_t)data;
|
||||
hadc->ChannelValid[channel] = 1;
|
||||
|
||||
// 2. Записываем в буфер если он есть
|
||||
if (hseq->data_buffer &&
|
||||
hseq->buffer_size > 0)
|
||||
{
|
||||
// Вычисляем offset для [ch][buffer_size]
|
||||
uint32_t offset = channel * hseq->buffer_size +
|
||||
hseq->buffer_count;
|
||||
hseq->data_buffer[offset] = (uint16_t)data;
|
||||
}
|
||||
|
||||
channels_processed++;
|
||||
|
||||
// Если это последний канал в секвенсоре - увеличиваем счетчик буфера
|
||||
if (req_num == last_request)
|
||||
{
|
||||
hseq->buffer_count++;
|
||||
|
||||
if(hseq->buffer_count == hseq->buffer_size/2)
|
||||
{
|
||||
if (conf->BuffHalfCallback)
|
||||
{
|
||||
conf->BuffHalfCallback();
|
||||
}
|
||||
}
|
||||
if(hseq->buffer_count >= hseq->buffer_size)
|
||||
{
|
||||
// Кольцевой буфер
|
||||
if(conf->buffer_circular)
|
||||
hseq->buffer_count = 0;
|
||||
else
|
||||
adc_seq_stop(hadc, SEQ_Num);
|
||||
|
||||
if (conf->BuffFullCallback)
|
||||
{
|
||||
conf->BuffFullCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Вызываем коллбек пользователя
|
||||
if (conf->SEQCpltCallback)
|
||||
{
|
||||
conf->SEQCpltCallback();
|
||||
}
|
||||
__adc_seq_fifo_read(hadc, SEQ_Num);
|
||||
}
|
||||
|
||||
// Обработка ошибок
|
||||
@@ -321,117 +358,127 @@ void adc_seq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
conf->ErrorCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// GPIO_ClearBits(GPIOA, GPIO_Pin_7);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Внутренняя функция для расчета загрузки FIFO буфера
|
||||
* @param hadc указатель на хендл АЦП
|
||||
* @param SEQ_Num номер секвенсора
|
||||
* @retval Кол-во данных FIFO буфера, или -1 если переполнение FIFO
|
||||
* @details Рассчитывает сколько данных накопится в fifo буфере за одно прерывание
|
||||
*/
|
||||
static int __adc_seq_calc_fifo_load(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
{
|
||||
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
|
||||
|
||||
int numb_of_data = 0;
|
||||
uint32_t numb_of_req = ((uint32_t)conf->SEQ_Init.ReqMax+1);
|
||||
uint32_t it_cnt = ((uint32_t)conf->ITCount+1);
|
||||
|
||||
|
||||
if(conf->SEQ_Init.RestartAverageEn)
|
||||
{
|
||||
numb_of_data = numb_of_req;
|
||||
}
|
||||
else
|
||||
{
|
||||
numb_of_data = it_cnt*numb_of_req;
|
||||
if(numb_of_data > 32) // Максимальный размер FIFO - 32 элемента, поэтому если слишком многшо данных за время работы перед прерыванием - то ошибка
|
||||
return -1;
|
||||
}
|
||||
|
||||
return numb_of_data;
|
||||
}
|
||||
/**
|
||||
* @brief Внутренняя функция для чтения данных из FIFO
|
||||
* @param hadc указатель на хендл АЦП
|
||||
* @param SEQ_Num номер секвенсора
|
||||
* @retval void
|
||||
* @details Автоматически достает данные из FIFO и складывает их в заданный буфер
|
||||
и в структуру hadc
|
||||
*/
|
||||
static void __adc_seq_fifo_read(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
|
||||
{
|
||||
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
|
||||
_ADC_SEQ_TypeDef *SEQx = &hadc->Instance->SEQ[SEQ_Num];
|
||||
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
|
||||
|
||||
// Последний запрос в секвенсоре
|
||||
uint32_t last_request = SEQx->SRQCTL_bit.RQMAX;
|
||||
uint32_t numb_of_request = last_request+1;
|
||||
|
||||
// Читаем все доступные данные из FIFO
|
||||
uint32_t fifo_size = ADC_SEQ_GetFIFOLoad(SEQ_Num);
|
||||
uint32_t req_num = ((int)ADC_SEQ_GetReqCurrent(SEQ_Num)-fifo_size)%(numb_of_request); // первая дата в fifo будет (следующий запрос - количество данных в буфере)
|
||||
while (ADC_SEQ_GetFIFOLoad(SEQ_Num))
|
||||
{
|
||||
uint32_t data = ADC_SEQ_GetFIFOData(SEQ_Num);
|
||||
|
||||
if(ADC_SEQ_GetFIFOLoad(SEQ_Num) == 0)
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
if ((int)req_num < ADC_SEQ_Req_Total)
|
||||
{
|
||||
ADC_CH_Num_TypeDef channel = conf->SEQ_Init.Req[req_num];
|
||||
|
||||
if ((int)channel < ADC_CH_Total)
|
||||
{
|
||||
// 1. Обновляем текущее значение
|
||||
hadc->ChannelData[channel] = (uint16_t)data;
|
||||
|
||||
// 2. Записываем в буфер если он есть
|
||||
if (hseq->data_buffer &&
|
||||
hseq->buffer_size > 0)
|
||||
{
|
||||
// Вычисляем offset для [ch][buffer_size]
|
||||
uint32_t offset = req_num * hseq->buffer_size +
|
||||
hseq->buffer_count;
|
||||
hseq->data_buffer[offset] = (uint16_t)data;
|
||||
}
|
||||
}
|
||||
|
||||
// Если это последний канал в секвенсоре - увеличиваем счетчик буфера
|
||||
if (req_num == last_request)
|
||||
{
|
||||
hseq->buffer_count++;
|
||||
|
||||
if(hseq->buffer_count == hseq->buffer_size/2)
|
||||
{
|
||||
if (conf->BuffHalfCallback)
|
||||
{
|
||||
conf->BuffHalfCallback();
|
||||
}
|
||||
}
|
||||
if(hseq->buffer_count >= hseq->buffer_size)
|
||||
{
|
||||
// Кольцевой буфер
|
||||
if(conf->BufferCircular)
|
||||
hseq->buffer_count = 0;
|
||||
else
|
||||
ADC_SEQ_Stop(hadc, SEQ_Num);
|
||||
|
||||
if (conf->BuffFullCallback)
|
||||
{
|
||||
conf->BuffFullCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Переход на Следующий канал
|
||||
req_num = (req_num+1)%numb_of_request;
|
||||
}
|
||||
|
||||
// Вызываем коллбек пользователя
|
||||
if (conf->SEQCpltCallback)
|
||||
{
|
||||
conf->SEQCpltCallback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////DIGITAL COMPARATORS/////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///**
|
||||
// * @brief Инициализация цифрового компаратора АЦП
|
||||
// * @param hadc указатель на хендл АЦП
|
||||
// * @param DC_Num номер компаратора
|
||||
// * @param NewConfig указатель на конфигурацию
|
||||
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
// */
|
||||
//OperationStatus adc_dc_init(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num, ADC_DC_ExtInit_TypeDef *NewConfig)
|
||||
//{
|
||||
// if(!hadc || !hadc->Instance)
|
||||
// return ERROR;
|
||||
//
|
||||
// if(NewConfig != NULL)
|
||||
// {
|
||||
// hadc->DC_Config[DC_Num] = NewConfig;
|
||||
// }
|
||||
//
|
||||
// if(hadc->DC_Config[DC_Num] == NULL)
|
||||
// {
|
||||
// return ERROR;
|
||||
// }
|
||||
//
|
||||
// // Инициализация компаратора
|
||||
// ADC_DC_Init(DC_Num, &hadc->DC_Config[DC_Num]->DC_Init);
|
||||
//
|
||||
// return OK;
|
||||
//}
|
||||
|
||||
|
||||
///**
|
||||
// * @brief Установка коллбека цифрового компаратора АЦП
|
||||
// * @param hadc указатель на хендл АЦП
|
||||
// * @param DC_Num номер компаратора
|
||||
// * @param cb_type тип коллбека
|
||||
// * @param Callback функция коллбека
|
||||
// * @retval OperationStatus
|
||||
// */
|
||||
//OperationStatus adc_dc_set_callback(ADC_HandleTypeDef* hadc, ADC_DC_Num_TypeDef DC_Num, ADC_CallbackTypeDef cb_type, void (*Callback)(void))
|
||||
//{
|
||||
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
|
||||
// return ERROR;
|
||||
//
|
||||
// switch(cb_type)
|
||||
// {
|
||||
// case ADC_Callback_DC:
|
||||
// hadc->DC_Config[DC_Num]->DC_TrigCallback = Callback;
|
||||
// break;
|
||||
// case ADC_Callback_Error:
|
||||
// hadc->DC_Config[DC_Num]->ErrorCallback = Callback;
|
||||
// break;
|
||||
// default:
|
||||
// return ERROR;
|
||||
// }
|
||||
// return OK;
|
||||
//}
|
||||
|
||||
|
||||
///**
|
||||
// * @brief Запуск цифрового компаратора АЦП
|
||||
// * @param hadc указатель на хендл АЦП
|
||||
// * @param DC_Num номер компаратора
|
||||
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
// */
|
||||
//OperationStatus adc_dc_start(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
|
||||
//{
|
||||
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
|
||||
// return ERROR;
|
||||
//
|
||||
// ADC_DC_ExtInit_TypeDef *conf = hadc->DC_Config[DC_Num];
|
||||
//
|
||||
// // Включаем выход компаратора
|
||||
// ADC_DC_OutputCmd(DC_Num, ENABLE);
|
||||
//
|
||||
// // Настраиваем прерывания если нужно
|
||||
// if(conf->IT == ENABLE)
|
||||
// {
|
||||
// ADC_DC_ITCmd(DC_Num, ENABLE);
|
||||
// }
|
||||
//
|
||||
// return OK;
|
||||
//}
|
||||
|
||||
///**
|
||||
// * @brief Остановка цифрового компаратора АЦП
|
||||
// * @param hadc указатель на хендл АЦП
|
||||
// * @param DC_Num номер компаратора
|
||||
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
// */
|
||||
//OperationStatus adc_dc_stop(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
|
||||
//{
|
||||
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
|
||||
// return ERROR;
|
||||
//
|
||||
// // Выключаем выход компаратора
|
||||
// ADC_DC_OutputCmd(DC_Num, DISABLE);
|
||||
//
|
||||
// // Выключаем прерывания
|
||||
// ADC_DC_ITCmd(DC_Num, DISABLE);
|
||||
//
|
||||
// return OK;
|
||||
//}
|
||||
|
||||
//void adc_dc_handler(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
|
||||
//{
|
||||
//}
|
||||
//-- ADC Digital Comparators API functions -------------------------------------
|
||||
|
||||
104
Core/App/adc.h
104
Core/App/adc.h
@@ -1,11 +1,15 @@
|
||||
/*==============================================================================
|
||||
* Инициализация таймеров с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file adc.h
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер ADC на основе PLIB035.
|
||||
* Данный файл содержит определения типов, структур и прототипы функций
|
||||
* для работы с ADC, включая:
|
||||
* + Структуры и typedef для ADC
|
||||
* + Прототипы функций для инициализации и API драйвера
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef __ADC_H
|
||||
#define __ADC_H
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
@@ -13,23 +17,30 @@
|
||||
#include "retarget_conf.h"
|
||||
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
// Дефайны для режима АЦП
|
||||
|
||||
|
||||
//-- Types ---------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Типы callback-функций ADC
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ADC_Callback_Seq,
|
||||
ADC_Callback_BuffHalf,
|
||||
ADC_Callback_BuffFull,
|
||||
ADC_Callback_DC,
|
||||
ADC_Callback_Error,
|
||||
ADC_Callback_SeqCplt, /*!< Преобразование секвенсора завершено */
|
||||
ADC_Callback_BuffHalf, /*!< Буфер заполнен наполовину */
|
||||
ADC_Callback_BuffFull, /*!< Буфер заполнен полностью */
|
||||
ADC_Callback_DCTrig, /*!< Компаратор сработал */
|
||||
ADC_Callback_Error, /*!< Ошибка */
|
||||
}ADC_CallbackTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Расширенная конфигурация секвенсора ADC
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ADC_SEQ_Init_TypeDef SEQ_Init; /* Стандартная конфигурация из PLIB */
|
||||
FunctionalState IT; /*!< Включить прерывания */
|
||||
uint8_t ITCount; /*!< Количество запросов для генерации прерывания */
|
||||
uint32_t buffer_circular; /*!< Циклический буфер */
|
||||
FunctionalState BufferCircular; /*!< Циклический буфер */
|
||||
|
||||
void (*SEQCpltCallback)(void); /*!< Вызывается при завершении секвенсора */
|
||||
void (*BuffHalfCallback)(void); /*!< Вызывается при заполнении половины буфера */
|
||||
@@ -37,63 +48,84 @@ typedef struct
|
||||
void (*ErrorCallback)(); /*!< Вызывается при ошибке */
|
||||
}ADC_SEQ_ExtInit_TypeDef;
|
||||
|
||||
/**
|
||||
* @brief Расширенная конфигурация компаратора ADC
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ADC_DC_Init_TypeDef DC_Init;
|
||||
FunctionalState IT; /*!< Включить прерывания */
|
||||
|
||||
void (*DC_TrigCallback); /*!< Вызывается при срабатывании компаратора */
|
||||
void (*ErrorCallback)(); /*!< Вызывается при ошибке */
|
||||
|
||||
|
||||
void (*ErrorCallback)(); /*!< Вызывается при ошибке */
|
||||
}ADC_DC_ExtInit_TypeDef;
|
||||
|
||||
/**
|
||||
* @brief Хендл секвенсора ADC
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ADC_SEQ_ExtInit_TypeDef *Config; /*!< Конфигурации секвенсоров */
|
||||
uint8_t running;
|
||||
ADC_SEQ_ExtInit_TypeDef *Config; /*!< Конфигурации секвенсоров */
|
||||
|
||||
|
||||
uint16_t *data_buffer; /*!< Указатель на буфер данных [ch][buffer_size]*/
|
||||
uint32_t buffer_size; /*!< Размер буфера (16-bit слова) */
|
||||
uint32_t buffer_count; /*!< Счетчик текущего индекса буфера */
|
||||
uint16_t *data_buffer; /*!< Указатель на буфер данных [ch][buffer_size]*/
|
||||
uint32_t buffer_size; /*!< Размер буфера (16-bit слова) */
|
||||
uint32_t buffer_count; /*!< Счетчик текущего индекса буфера */
|
||||
}ADC_SEQ_HandleTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Хендл компаратора ADC
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ADC_DC_ExtInit_TypeDef *Config; /*!< Конфигурации компараторов */
|
||||
uint8_t running;
|
||||
}ADC_DC_HandleTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Хендл ADC
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
|
||||
ADC_TypeDef *Instance; /*!< Регистры ADC */
|
||||
|
||||
|
||||
ADC_SEQ_HandleTypeDef SEQ[ADC_SEQ_Total]; /*!< Хендл секвенсоров */
|
||||
ADC_DC_ExtInit_TypeDef DC[ADC_DC_Total]; /*!< Хендл компараторов */
|
||||
|
||||
// Буферы данных для каждого канала (актуальные значения)
|
||||
/* ===== Channels ===== */
|
||||
uint16_t ChannelData[ADC_CH_Total]; /*!< Текущие значения каналов */
|
||||
uint8_t ChannelValid[ADC_CH_Total]; /*!< Флаги валидности данных */
|
||||
}ADC_HandleTypeDef;
|
||||
//-- External handles ----------------------------------------------------------
|
||||
extern ADC_HandleTypeDef hadc;
|
||||
|
||||
//-- Exported functions prototypes ---------------------------------------------
|
||||
/* Первичная инициализация ADC */
|
||||
void adc_init_first(void);
|
||||
|
||||
/* Sequencer Init functions*/
|
||||
|
||||
/* Инициализация секвенсора АЦП */
|
||||
OperationStatus adc_seq_init(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_SEQ_ExtInit_TypeDef *NewConfig);
|
||||
OperationStatus adc_seq_set_callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_CallbackTypeDef cb_type, void (*Callback)(void));
|
||||
/* Обработчик прерываний секвенсора */
|
||||
void adc_seq_irq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
|
||||
OperationStatus adc_seq_start(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num, uint16_t (*data_buffer)[], uint32_t buffer_size);
|
||||
OperationStatus adc_seq_stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
/* Sequencer API functions*/
|
||||
|
||||
uint16_t adc_get_channel_value(ADC_HandleTypeDef *hadc, ADC_CH_Num_TypeDef channel);
|
||||
void adc_sw_start(void);
|
||||
/* Установка коллбека секвенсора АЦП */
|
||||
OperationStatus ADC_SEQ_Set_Callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_CallbackTypeDef CallbackType, void (*Callback)(void));
|
||||
|
||||
/* Запуск секвенсора АЦП с буфером */
|
||||
OperationStatus ADC_SEQ_Start(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num, uint16_t (*data_buffer)[], uint32_t buffer_size);
|
||||
/* Остановка секвенсора АЦП */
|
||||
OperationStatus ADC_SEQ_Stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
|
||||
/* Получение текущего значения канала */
|
||||
uint16_t ADC_Get_ChannelValue(ADC_HandleTypeDef *hadc, ADC_CH_Num_TypeDef channel);
|
||||
/* Программный запуск преобразования секвенсора */
|
||||
void ADC_SEQ_SoftwareStart(void);
|
||||
|
||||
|
||||
// Обработчики прерываний
|
||||
void adc_seq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num);
|
||||
|
||||
|
||||
/* Comparator API functions*/
|
||||
|
||||
void adc_dc_handler(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num);
|
||||
#endif /*__ADC_H*/
|
||||
|
||||
378
Core/App/gpio.c
378
Core/App/gpio.c
@@ -1,19 +1,65 @@
|
||||
/*==============================================================================
|
||||
* Инициализация портов с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* Конфигурация портов настраивается в gpio.h
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file gpio.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер GPIO на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию портов GPIOA и GPIOB
|
||||
* + Функции для работы со светодиодами:
|
||||
* - Инициализацию структуры светодиода
|
||||
* - Включение, выключение, переключение светодиода
|
||||
* - Динамические режимы: моргание и плавное затухание
|
||||
* + Функции для работы с кнопками:
|
||||
* - Инициализацию структуры кнопки
|
||||
* - Чтение состояния кнопки с защитой от дребезга
|
||||
* + Утилитарные функции для получения конфигурации пинов
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены массивы конфигурации gpioa_config и gpiob_config в periph_config.h
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка периферии (periph_config.h):
|
||||
(+) Определить массивы GPIO_Init_TypeDef для портов:
|
||||
gpioa_config[32], gpiob_config[32]
|
||||
(+) Настроить режим пинов: Input, Output, AltFunc и другие функции
|
||||
|
||||
2. Инициализация GPIO:
|
||||
(+) gpio_init() — инициализация портов GPIOA и GPIOB
|
||||
|
||||
3. Работа со светодиодами:
|
||||
(+) GPIO_LED_Init(&led, GPIOA, GPIO_PIN_5, SET) — инициализация светодиода
|
||||
(+) GPIO_LED_On(&led) — включение светодиода
|
||||
(+) GPIO_LED_Off(&led) — выключение светодиода
|
||||
(+) GPIO_LED_Toggle(&led) — переключение светодиода
|
||||
(+) GPIO_LED_Blink_Start(&led, 500) — запуск моргания (период 500 мс)
|
||||
(+) GPIO_LED_Fading_Start(&led, 1000) — запуск плавного затухания (период 1 секунда)
|
||||
(+) GPIO_LED_Dynamic_Handle(&led) — обработка динамических режимов в основном цикле
|
||||
|
||||
4. Работа с кнопками:
|
||||
(+) GPIO_Switch_Init(&sw, GPIOB, GPIO_PIN_0, SET) — инициализация кнопки
|
||||
(+) GPIO_Read_Switch(&sw) — чтение состояния кнопки с фильтрацией
|
||||
|
||||
5. Утилитарные функции:
|
||||
(+) gpio_get_init(GPIOA, GPIO_PIN_5) — получение конфигурации пина
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "periph_config.h"
|
||||
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
//-- GPIO init functions -------------------------------------------------------
|
||||
void gpio_init(void)
|
||||
{
|
||||
RCU_AHBClkCmd(RCU_AHBClk_GPIOA, ENABLE);
|
||||
@@ -36,43 +82,12 @@ void gpio_init(void)
|
||||
{
|
||||
GPIO_Init(GPIOB, &gpiob_config[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// GPIO_StructInit(&gpio_init);
|
||||
// gpio_init.Digital = ENABLE;
|
||||
// GPIO_Init(GPIOA, &gpio_init);
|
||||
// GPIO_Init(GPIOB, &gpio_init);
|
||||
//
|
||||
// /* Инициализация выходных пинов Пуш-Пулл */
|
||||
// gpio_init.Out = ENABLE;
|
||||
// gpio_init.OutMode = GPIO_OutMode_PP;
|
||||
//
|
||||
// gpio_init.Pin = GPIO_OUT_PP_PA_PINS;
|
||||
// GPIO_Init(GPIOA, &gpio_init);
|
||||
// gpio_init.Pin = GPIO_OUT_PP_PB_PINS;
|
||||
// GPIO_Init(GPIOB, &gpio_init);
|
||||
//
|
||||
// /* Инициализация выходных пинов Открытый сток */
|
||||
// gpio_init.Out = ENABLE;
|
||||
// gpio_init.OutMode = GPIO_OutMode_OD;
|
||||
//
|
||||
// gpio_init.Pin = GPIO_OUT_OD_PA_PINS;
|
||||
// GPIO_Init(GPIOA, &gpio_init);
|
||||
// gpio_init.Pin = GPIO_OUT_OD_PB_PINS;
|
||||
// GPIO_Init(GPIOB, &gpio_init);
|
||||
}
|
||||
|
||||
|
||||
GPIO_Init_TypeDef *gpio_get_init(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
|
||||
{
|
||||
uint8_t pin_index = __builtin_ctz(GPIO_Pin);
|
||||
uint8_t pin_index = (31 - __CLZ(GPIO_Pin & -GPIO_Pin));
|
||||
|
||||
if (GPIOx == GPIOA)
|
||||
{
|
||||
@@ -93,3 +108,282 @@ GPIO_Init_TypeDef *gpio_get_init(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-- GPIO LED functions --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализировать светодиод (структуру светодиода)
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param GPIOx Указатель на структуру порта для светодиода
|
||||
* @param GPIO_PIN_X Пин для светодиода
|
||||
* @param LED_ActiveLevel Состояния пина, при котором светодиод будет включен
|
||||
*/
|
||||
OperationStatus GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, BitState LED_ActiveLevel)
|
||||
{
|
||||
if(!led || !GPIOx ||!GPIO_PIN_X)
|
||||
return ERROR;
|
||||
|
||||
led->LED_Port = GPIOx;
|
||||
led->LED_Pin = GPIO_PIN_X;
|
||||
led->LED_ActiveLvl = LED_ActiveLevel;
|
||||
|
||||
GPIO_LED_Off(led);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Включить светодиод
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @return Operation Status
|
||||
*/
|
||||
OperationStatus GPIO_LED_On(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
led->state = LED_IS_ON;
|
||||
GPIO_WriteBit(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
/**
|
||||
* @brief Выключить светодиод
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @return Operation Status
|
||||
*/
|
||||
OperationStatus GPIO_LED_Off(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
led->state = LED_IS_OFF;
|
||||
BitState offstate = (led->LED_ActiveLvl == SET)? CLEAR: SET;
|
||||
GPIO_WriteBit(led->LED_Port, led->LED_Pin, offstate);
|
||||
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Переключить светодиод
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @return Operation Status
|
||||
*/
|
||||
OperationStatus GPIO_LED_Toggle(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
|
||||
if(led->state == LED_IS_ON || led->state == LED_IS_OFF)
|
||||
{
|
||||
if(led->state == LED_IS_OFF)
|
||||
led->state = LED_IS_ON;
|
||||
else
|
||||
led->state = LED_IS_OFF;
|
||||
|
||||
GPIO_ToggleBits(led->LED_Port, led->LED_Pin);
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выставить светодиод по переменной
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param led_state Состояние светодиода
|
||||
* @return Operation Status
|
||||
*/
|
||||
OperationStatus GPIO_LED_Set(GPIO_LEDTypeDef *led, uint8_t led_state)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
if(led_state)
|
||||
{
|
||||
return GPIO_LED_On(led);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GPIO_LED_Off(led);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Активировать моргание светодиодом
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param period Период плавного моргания светодиода
|
||||
* @return Operation Status
|
||||
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
|
||||
*/
|
||||
OperationStatus GPIO_LED_Blink_Start(GPIO_LEDTypeDef *led, uint32_t period)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
led->state = LED_IS_BLINKING;
|
||||
led->LED_Period = period;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Активировать моргание светодиодом
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param period Период плавного моргания светодиода
|
||||
* @return Operation Status
|
||||
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
|
||||
*/
|
||||
OperationStatus GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return ERROR;
|
||||
|
||||
led->state = LED_IS_FADING;
|
||||
led->LED_Period = period;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//uint8_t LED_PWM_FADING_DUTYS[LED_PWM_TICKS] = {0 1 2 3 4 5 6 7 8 9 10 11 12 }
|
||||
/**
|
||||
* @brief Управление динамическими режимами свечения светодиода
|
||||
* @param Указатель на структуру светодиода
|
||||
* @details Функция моргает/плавно моргает светодиодом в неблокирующем режиме
|
||||
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила тики
|
||||
* и в нужный момент переключала светодиод
|
||||
*/
|
||||
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(!led || !led->LED_Port || !led->LED_Pin)
|
||||
return;
|
||||
|
||||
/* Режим моргания светодиода */
|
||||
if(led->state == LED_IS_BLINKING)
|
||||
{
|
||||
uint32_t tickcurrent = millis();
|
||||
/* Ожидание истечения периода моргания */
|
||||
if((tickcurrent - led->tickprev) > led->LED_Period)
|
||||
{
|
||||
/* Моргание */
|
||||
GPIO_ToggleBits(led->LED_Port, led->LED_Pin);
|
||||
|
||||
led->tickprev = tickcurrent;
|
||||
}
|
||||
}
|
||||
/* Режим плавного моргания светодиода */
|
||||
else if(led->state == LED_IS_FADING)
|
||||
{
|
||||
static unsigned direction = 0;
|
||||
static int duty = 0;
|
||||
uint32_t tickcurrent = millis();
|
||||
/* Ожидание момента изменения яркости */
|
||||
/* Период ШИМ 20 мс, поэтому менять яроксть надо 40 раз за период (туда обратно) */
|
||||
if((tickcurrent - led->tickprev) > led->LED_Period/(LED_PWM_TICKS*2))
|
||||
{
|
||||
/* Формирование разтухания */
|
||||
if(direction == 0)
|
||||
{
|
||||
if(++duty >= LED_PWM_TICKS)
|
||||
{
|
||||
direction = 1;
|
||||
duty = LED_PWM_TICKS;
|
||||
}
|
||||
}
|
||||
/* Формирование затухания */
|
||||
else
|
||||
{
|
||||
if(--duty <= 0)
|
||||
{
|
||||
direction = 0;
|
||||
duty = 0;
|
||||
}
|
||||
}
|
||||
led->tickprev = tickcurrent;
|
||||
}
|
||||
/* Формирование ШИМ для изменения яркости */
|
||||
int duty_crt = (duty*duty/LED_PWM_TICKS);
|
||||
if(tickcurrent%LED_PWM_TICKS < duty_crt)
|
||||
{
|
||||
GPIO_WriteBit(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
|
||||
}
|
||||
else
|
||||
{
|
||||
BitState offstate = (led->LED_ActiveLvl == SET)? CLEAR: SET;
|
||||
GPIO_WriteBit(led->LED_Port, led->LED_Pin, offstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-- GPIO Switch functions -----------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализировать кнопку (структуру кнопки)
|
||||
* @param sw Указатель на структуру кнопки
|
||||
* @param GPIOx Указатель на структуру порта для кнопки
|
||||
* @param GPIO_PIN_X Пин для кнопки
|
||||
* @param SW_ActiveLevel Состояния пина, когда кнопка нажата
|
||||
* @return Operation Status
|
||||
*/
|
||||
OperationStatus GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, BitState SW_ActiveLevel)
|
||||
{
|
||||
if(!sw || !GPIOx || !GPIO_PIN_X)
|
||||
return ERROR;
|
||||
|
||||
sw->Sw_Port = GPIOx;
|
||||
sw->Sw_Pin = GPIO_PIN_X;
|
||||
sw->Sw_ActiveLvl = SW_ActiveLevel;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Считать состоянии кнопки
|
||||
* @param sw Указатель на структуру кнопки
|
||||
* @return 1 - если кнопка нажата,
|
||||
* 0 - если отжата,
|
||||
* -1 - если ошибка
|
||||
* @details Функция включает в себя неблокирующую проверку на дребезг
|
||||
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила состояние кнопки
|
||||
*/
|
||||
int GPIO_Read_Switch(GPIO_SwitchTypeDef *sw)
|
||||
{
|
||||
if(!sw || !sw->Sw_Port || !sw->Sw_Pin)
|
||||
return -1;
|
||||
|
||||
int current_level = (GPIO_ReadBit(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl);
|
||||
|
||||
if(sw->Sw_FilterDelay) // если включена защита от дребезга
|
||||
{
|
||||
// Если таймер не запущен и состояние изменилось - запускаем таймер
|
||||
if(sw->tickprev == 0 && current_level != sw->Sw_CurrentState)
|
||||
{
|
||||
sw->tickprev = millis();
|
||||
}
|
||||
|
||||
// Если таймер запущен
|
||||
if(sw->tickprev != 0)
|
||||
{
|
||||
// Проверяем, прошел ли достаточный интервал для фильтрации
|
||||
if((millis() - sw->tickprev) >= sw->Sw_FilterDelay)
|
||||
{
|
||||
// Обновляем состояние только если оно все еще отличается
|
||||
if(current_level != sw->Sw_CurrentState)
|
||||
{
|
||||
sw->Sw_CurrentState = current_level;
|
||||
}
|
||||
// Останавливаем таймер в любом случае
|
||||
sw->tickprev = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // если нет защиты от дребезга
|
||||
{
|
||||
sw->Sw_CurrentState = current_level;
|
||||
}
|
||||
return sw->Sw_CurrentState;
|
||||
}
|
||||
|
||||
155
Core/App/gpio.h
155
Core/App/gpio.h
@@ -1,12 +1,16 @@
|
||||
/*==============================================================================
|
||||
* Инициализация портов с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* Реализация функций инициализации портов находится в gpio.c
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file gpio.h
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер GPIO на основе PLIB035.
|
||||
* Данный файл содержит определения типов, структур и прототипы функций
|
||||
* для работы с UART, включая:
|
||||
* + Структуры и typedef для работы с кнопками и светодиодами
|
||||
* + Макросы для конфигурации режима пинов
|
||||
* + Прототипы функций для инициализации и API драйвера
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef __GPIO_H
|
||||
#define __GPIO_H
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
@@ -21,8 +25,141 @@
|
||||
#define GPIO_PinMode_AltFunc DISABLE, ENABLE, ENABLE
|
||||
//#define GPIO_PinMode_Analog DISABLE, DISABLE, DISABLE
|
||||
|
||||
#ifndef LED_PWM_TICKS
|
||||
#define LED_PWM_TICKS 15 ///< Количество тиков в периоде ШИМ
|
||||
#endif
|
||||
//-- Types ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Режимы работы светодиода
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LED_IS_OFF = 0, ///< Светодиод выключен
|
||||
LED_IS_ON = 1, ///< Светодиод включен
|
||||
LED_IS_BLINKING = 2, ///< Моргание светодиодом
|
||||
LED_IS_FADING = 3, ///< Плавное моргание светодиодом
|
||||
}GPIO_LEDStateTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура светодиода
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GPIO_LEDStateTypeDef state; ///< Текущий режим работы светодиода
|
||||
|
||||
GPIO_TypeDef *LED_Port; ///< GPIO порт ножки светодиода
|
||||
uint32_t LED_Pin; ///< GPIO пин ножки светодиода
|
||||
|
||||
BitState LED_ActiveLvl; ///< Активный уровень ножки (при котором светодиод горит)
|
||||
uint32_t LED_Period; ///< Период моргания светодиода
|
||||
|
||||
uint32_t tickprev;
|
||||
}GPIO_LEDTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура кнопки
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GPIO_TypeDef *Sw_Port; ///< GPIO порт ножки кнопки
|
||||
uint32_t Sw_Pin; ///< GPIO пин ножки кнопки
|
||||
|
||||
BitState Sw_ActiveLvl; ///< Активный уровень ножки (при котором кнопка нажата)
|
||||
uint32_t Sw_CurrentState; ///< Текущее состояние кнопки
|
||||
uint32_t Sw_FilterDelay; ///< Фильтр от дребезга (в мс)
|
||||
|
||||
uint32_t tickprev;
|
||||
}GPIO_SwitchTypeDef;
|
||||
|
||||
|
||||
//-- Exported functions prototypes ---------------------------------------------
|
||||
|
||||
/* Init functions */
|
||||
|
||||
void gpio_init(void);
|
||||
GPIO_Init_TypeDef *gpio_get_init(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
|
||||
|
||||
|
||||
/* API functions*/
|
||||
|
||||
/**
|
||||
* @addtogroup GPIO_SWITCH Switch tools
|
||||
* @brief Функции для работы с GPIO, как с кнопкой
|
||||
* @par Пример использования:
|
||||
@code
|
||||
MX_GPIO_Init(); // инициализация пина аппаратная
|
||||
|
||||
// Инициализация кнопки на порте GPIOB, пин 0, активный уровень 1
|
||||
GPIO_SwitchTypeDef sw1;
|
||||
GPIO_Switch_Init(&sw1, GPIOB, GPIO_PIN_0, 1); // или дефайн SW_ON/SW_OFF
|
||||
|
||||
// Считываем состояние кнопки
|
||||
if(GPIO_Read_Switch(&sw1))
|
||||
{
|
||||
// Кнопка нажата
|
||||
LED_ON();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Кнопка отжата
|
||||
LED_OFF();
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Инициализировать кнопку (структуру кнопки) */
|
||||
OperationStatus GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, BitState SW_On_State);
|
||||
/* Считать состоянии кнопки запуска */
|
||||
int GPIO_Read_Switch(GPIO_SwitchTypeDef *swstart);
|
||||
|
||||
/** GPIO_SWITCH
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup GPIO_LEDS LED tools
|
||||
* @brief Функции для работы с GPIO, для управления светодиодом
|
||||
* @par Пример использования:
|
||||
@code
|
||||
// Инициализация светодиода на порте GPIOA, пин 5, активный уровень 0
|
||||
GPIO_LEDTypeDef led;
|
||||
GPIO_LED_Init(&led, GPIOA, GPIO_PIN_5, 0); // или дефайн LED_ON/LED_OFF
|
||||
|
||||
// Включение светодиода
|
||||
GPIO_LED_On(&led);
|
||||
|
||||
// Запуск моргания
|
||||
GPIO_LED_Blink_Start(&led, 500); // Период 500 мс
|
||||
|
||||
// В основном цикле
|
||||
while (1) {
|
||||
GPIO_LED_Dynamic_Handle(&led);
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Инициализировать светодиод (структуру светодиода) */
|
||||
OperationStatus GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, BitState LED_On_State);
|
||||
/* Включить светодиод */
|
||||
OperationStatus GPIO_LED_On (GPIO_LEDTypeDef *led);
|
||||
/* Выключить светодиод */
|
||||
OperationStatus GPIO_LED_Off (GPIO_LEDTypeDef *led);
|
||||
/* Переключить светодиод */
|
||||
OperationStatus GPIO_LED_Toggle(GPIO_LEDTypeDef *led);
|
||||
/* Выставить светодиод по переменной */
|
||||
OperationStatus GPIO_LED_Set (GPIO_LEDTypeDef *led, uint8_t led_state);
|
||||
/* Активировать моргание светодиодом */
|
||||
OperationStatus GPIO_LED_Blink_Start (GPIO_LEDTypeDef *led, uint32_t period);
|
||||
/* Активировать моргание светодиодом */
|
||||
OperationStatus GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period);
|
||||
/* Управление динамическими режимами свечения светодиода */
|
||||
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led);
|
||||
|
||||
/** GPIO_LEDS
|
||||
* @}
|
||||
*/
|
||||
#endif /*__GPIO_H*/
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "main.h"
|
||||
|
||||
void restart_receive(void);
|
||||
void heartbit(void);
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
uint8_t rxbuff[10] = {0};
|
||||
uint16_t adc_buff[2][100];
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
void periph_init()
|
||||
{
|
||||
@@ -26,60 +23,29 @@ void periph_init()
|
||||
#ifdef RETARGET
|
||||
retarget_init();
|
||||
#endif
|
||||
NVIC_SetAllPriorities();
|
||||
printf("\nAll peripherals inited, SYSCLK = %3d MHz\n", (int)(SystemCoreClock / 1E6));
|
||||
|
||||
|
||||
uart_set_callback(&huart1, UART_Callback_Rx, &restart_receive);
|
||||
uart_start(&huart1, UART_FIFOLevel_1_8, UART_FIFOLevel_1_8);
|
||||
|
||||
tmr_set_callback(&htmr2, 0, &heartbit);
|
||||
tmr_start(&htmr0);
|
||||
tmr_start(&htmr1);
|
||||
tmr_start(&htmr2);
|
||||
adc_seq_start(&hadc, ADC_SEQ_Num_0, adc_buff, 100);
|
||||
}
|
||||
|
||||
//-- Main ----------------------------------------------------------------------
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
periph_init();
|
||||
uint8_t cnt;
|
||||
uart_receive_it(&huart1, rxbuff, sizeof(rxbuff));
|
||||
uint32_t prev_tick;
|
||||
tmr_delay_start(&htmr0, &prev_tick);
|
||||
while (1) {
|
||||
if(tmr_delay_done(&htmr0, 1000000, &prev_tick))
|
||||
{
|
||||
tmr_delay_start(&htmr0, &prev_tick);
|
||||
GPIO_ToggleBits(GPIOA, GPIO_Pin_8);
|
||||
adc_sw_start();
|
||||
}
|
||||
tmr_delay(&htmr0, 100000);
|
||||
GPIO_ToggleBits(GPIOA, GPIO_Pin_7);
|
||||
// uart_transmit_it(&huart1, (uint8_t*)"Hello World: ", sizeof("Hello World: ")-1);
|
||||
// uart_transmit_it(&huart1, (uint8_t*)"delay 500\r\n", sizeof("delay 500\r\n")-1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
};
|
||||
//return 0;
|
||||
}
|
||||
|
||||
void restart_receive(void)
|
||||
{
|
||||
uart_receive_it(&huart1, rxbuff, sizeof(rxbuff));
|
||||
uart_transmit_it(&huart1, rxbuff, sizeof(rxbuff));
|
||||
}
|
||||
|
||||
void heartbit(void)
|
||||
{
|
||||
uart_transmit(&huart1, (uint8_t *)"\r\nTick 1 sec\r\n", sizeof("\r\nTick 1 sec\r\n")-1, 1000);
|
||||
}
|
||||
|
||||
//-- Assert --------------------------------------------------------------------
|
||||
void Error_Handler(void)
|
||||
{
|
||||
__disable_irq();
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined USE_FULL_ASSERT
|
||||
|
||||
@@ -1,19 +1,96 @@
|
||||
/*==============================================================================
|
||||
* Инициализация тактирования с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sysclk.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер тактирования системы на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию системного тактирования (PLL, осцилляторы)
|
||||
* + Настройку частоты ядра и периферии
|
||||
* + Управление системным таймером (SysTick)
|
||||
* + Функции для работы со временем (millis, micros)
|
||||
* + Систему периодических коллбеков
|
||||
* + Настройку тактирования периферии
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены константы SYSCLK_CORE_CLOCK_MHZ и SYSCLK_Oscil_Type в periph_config.h
|
||||
* - Определен тип системного тика SYSCLK_TickType в periph_config.h
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка периферии (periph_config.h):
|
||||
(+) Определить SYSCLK_CORE_CLOCK_MHZ - частота ядра в МГц (например, 100)
|
||||
(+) Определить SYSCLK_Oscil_Type - тип осциллятора (RCU_Oscil_OSE или RCU_Oscil_OSI)
|
||||
(+) Определить SYSCLK_TickType - тип системного тика (SYSCLK_Tick_1us, SYSCLK_Tick_1ms и т.д.)
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
2. Инициализация тактирования:
|
||||
(+) sysclk_init() — обязательный вызов в начале программы
|
||||
- Автоматически настраивает PLL для заданной частоты
|
||||
- Настраивает SysTick для генерации системных тиков
|
||||
- Обновляет SystemCoreClock
|
||||
|
||||
3. Работа со временем:
|
||||
(+) millis() — получение текущего времени в миллисекундах
|
||||
(+) micros() — получение текущего времени в микросекундах
|
||||
(+) sysclk_irq_handler() — обработчик прерываний SysTick (должен вызываться из SysTick_Handler)
|
||||
|
||||
4. Система коллбеков:
|
||||
(+) SYSCLK_Set_Callback() — добавление периодического коллбека
|
||||
- Коллбеки автоматически вызываются в sysclk_irq_handler() с заданным периодом
|
||||
- Максимальное количество коллбеков: SYSCLK_NUMB_OF_CUSTOM_CALLBACKS
|
||||
|
||||
5. Настройка тактирования Периферии:
|
||||
(+) АЦП: rcu_set_clock_adc(ClkSrc, ClkMHz, state)
|
||||
- ClkSrc: источник тактирования (RCU_PeriphClk_OSEClk, RCU_PeriphClk_PLLClk и т.д.)
|
||||
- ClkMHz: желаемая частота ADC в МГц
|
||||
- state: включение/выключение тактирования
|
||||
|
||||
6. Особенности работы:
|
||||
(+) Системные тики работают на основе SysTick
|
||||
(+) Поддерживаются различные периоды тиков от 1 мкс до 100 мс
|
||||
(+) Переполнение счетчиков происходит через ~49 дней
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "periph_config.h"
|
||||
|
||||
__IO uint32_t uwTick; // Milliseconds ticks
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/** @brief Счетчик миллисекунд */
|
||||
__IO uint32_t msTick = 0;
|
||||
|
||||
/** @brief Счетчик микросекунд */
|
||||
__IO uint32_t usTick = 0;
|
||||
|
||||
/** @brief Инкремент для миллисекунд */
|
||||
static __IO uint32_t msTickInc = 0;
|
||||
|
||||
/** @brief Инкремент для микросекунд */
|
||||
static __IO uint32_t usTickInc = 0;
|
||||
|
||||
/** @brief Обработчик системных коллбеков */
|
||||
static SYSCLK_CallbackHandleTypeDef hsyscb = {0};
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
|
||||
//-- Private function prototypes -----------------------------------------------
|
||||
static inline void millis_inc(void);
|
||||
static inline void micros_inc(void);
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
/**
|
||||
* @brief Инициализация системного тактирования.
|
||||
* @details Настраивает PLL, SysTick и счетчики времени.
|
||||
* Должна быть вызвана первой в функции main().
|
||||
*/
|
||||
void sysclk_init(void)
|
||||
{
|
||||
OperationStatus status;
|
||||
@@ -23,41 +100,158 @@ void sysclk_init(void)
|
||||
Error_Handler();
|
||||
}
|
||||
SystemCoreClockUpdate();
|
||||
RCU_ClkOutConfig(RCU_SysPeriphClk_PLLClk, 1, ENABLE);
|
||||
RCU_ClkOutCmd(ENABLE);
|
||||
// RCU_ClkOutConfig(RCU_SysPeriphClk_PLLClk, 1, ENABLE);
|
||||
// RCU_ClkOutCmd(ENABLE);
|
||||
|
||||
/* Прерывание должно быть каждую миллисекунду:
|
||||
Для тактирования N Гц это каждый N / 1000 тик */
|
||||
SysTick_Config(SYSCLK_CORE_CLOCK_MHZ*__MHZ/1000);
|
||||
SysTick_Config(SYSCLK_CORE_CLOCK_MHZ*__MHZ/SYSCLK_TickType);
|
||||
switch(SYSCLK_TickType)
|
||||
{
|
||||
case SYSCLK_Tick_1us:
|
||||
usTickInc = 1;
|
||||
msTickInc = 1;
|
||||
break;
|
||||
case SYSCLK_Tick_10us:
|
||||
usTickInc = 10;
|
||||
msTickInc = 1;
|
||||
break;
|
||||
case SYSCLK_Tick_100us:
|
||||
usTickInc = 100;
|
||||
msTickInc = 1;
|
||||
break;
|
||||
case SYSCLK_Tick_1ms:
|
||||
usTickInc = 1000;
|
||||
msTickInc = 1;
|
||||
break;
|
||||
case SYSCLK_Tick_10ms:
|
||||
usTickInc = 10000;
|
||||
msTickInc = 10;
|
||||
break;
|
||||
case SYSCLK_Tick_100ms:
|
||||
usTickInc = 100000;
|
||||
msTickInc = 100;
|
||||
break;
|
||||
default:
|
||||
/* Должен быть определен в periph_config.h */
|
||||
Error_Handler();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Общий обработчик прерываний SysClock
|
||||
* @details Обрабатывает мс и мкс и вызывает коллбеки
|
||||
*/
|
||||
void sysclk_irq_handler(void)
|
||||
{
|
||||
static uint32_t usAccumulator = 0; // Накопитель мкс
|
||||
/* Инкремент микросекунд */
|
||||
micros_inc();
|
||||
|
||||
if(msTickInc == 1)
|
||||
{
|
||||
/* Аккумулятивный метод для миллисекунд (без деления) */
|
||||
usAccumulator += usTickInc;
|
||||
if (usAccumulator >= 1000) {
|
||||
millis_inc();
|
||||
usAccumulator -= 1000; // Вычитание быстрее деления
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
millis_inc();
|
||||
}
|
||||
|
||||
/* Вызов зарегистрированных коллбеков */
|
||||
for(int i = 0; i < hsyscb.CallbackInUse; i++)
|
||||
{
|
||||
if(hsyscb.Callback[i] != NULL)
|
||||
{
|
||||
/* Проверка истекшего времени */
|
||||
uint32_t elapsed = msTick - hsyscb.CallbackPrevMs[i];
|
||||
if(elapsed >= hsyscb.CallbackPeriod[i])
|
||||
{
|
||||
/* Обновление времени последнего вызова и вызов коллбека */
|
||||
hsyscb.CallbackPrevMs[i] = msTick;
|
||||
hsyscb.Callback[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Добавление периодического коллбека.
|
||||
* @param Callback Указатель на функцию-коллбек
|
||||
* @param PeriodInMs Период вызова коллбека в миллисекундах
|
||||
* @retval OperationStatus OK при успехе, ERROR при ошибке
|
||||
* @note Максимальное количество коллбеков: SYSCLK_NUMB_OF_CUSTOM_CALLBACKS
|
||||
* @note Минимальный период: текущий период тика SysTick
|
||||
*/
|
||||
OperationStatus SYSCLK_Set_Callback(void (*Callback)(void), uint32_t PeriodInMs)
|
||||
{
|
||||
/* Проверка валидности указателя на функцию */
|
||||
if(Callback == NULL)
|
||||
return ERROR;
|
||||
|
||||
/* Проверка минимального периода */
|
||||
if(PeriodInMs < msTickInc)
|
||||
return ERROR;
|
||||
|
||||
/* Проверка доступности свободных слотов */
|
||||
if(hsyscb.CallbackInUse >= SYSCLK_NUMB_OF_CUSTOM_CALLBACKS)
|
||||
return ERROR;
|
||||
|
||||
/* Регистрация коллбека */
|
||||
hsyscb.Callback[hsyscb.CallbackInUse] = Callback;
|
||||
hsyscb.CallbackPeriod[hsyscb.CallbackInUse] = PeriodInMs;
|
||||
hsyscb.CallbackPrevMs[hsyscb.CallbackInUse] = msTick;
|
||||
|
||||
hsyscb.CallbackInUse++;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получение текущего времени в миллисекундах.
|
||||
* @retval uint32_t Текущее время в миллисекундах
|
||||
* @note Переполнение происходит через ~49 дней
|
||||
*/
|
||||
uint32_t millis(void)
|
||||
{
|
||||
return uwTick;
|
||||
}
|
||||
void millis_inc(void)
|
||||
{
|
||||
uwTick++;
|
||||
return msTick;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получение текущего времени в микросекундах.
|
||||
* @retval uint32_t Текущее время в микросекундах
|
||||
* @note Переполнение происходит через ~71 минуту
|
||||
*/
|
||||
uint32_t micros(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void micros_inc(void)
|
||||
{
|
||||
uwTick++;
|
||||
return usTick;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Настройка тактирования АЦП.
|
||||
* @param ClkSrc Источник тактирования (RCU_PeriphClk_TypeDef)
|
||||
* @param ClkMHz Желаемая частота АЦП в МГц
|
||||
* @param state Состояние (ENABLE/DISABLE)
|
||||
* @retval OperationStatus OK при успехе, ERROR при ошибке
|
||||
* @note Временное отключает тактирование АЦП во время настройки
|
||||
*/
|
||||
OperationStatus rcu_set_clock_adc(RCU_PeriphClk_TypeDef ClkSrc, float ClkMHz, FunctionalState state)
|
||||
{
|
||||
RCU_ADCClkCmd(DISABLE);
|
||||
uint32_t adc_raw_clock = 0;
|
||||
float adc_clock_div = 0;
|
||||
|
||||
/* Отключение тактирования АЦП для настройки */
|
||||
RCU_ADCClkCmd(DISABLE);
|
||||
|
||||
/* Определение частоты источника тактирования */
|
||||
switch(ClkSrc)
|
||||
{
|
||||
case RCU_PeriphClk_OSEClk:
|
||||
@@ -72,12 +266,41 @@ OperationStatus rcu_set_clock_adc(RCU_PeriphClk_TypeDef ClkSrc, float ClkMHz, Fu
|
||||
case RCU_PeriphClk_PLLDivClk:
|
||||
adc_raw_clock = RCU_GetPLLDivClkFreq();
|
||||
break;
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
adc_clock_div = adc_raw_clock/(ClkMHz*__MHZ);
|
||||
|
||||
/* Расчет делителя частоты */
|
||||
adc_clock_div = adc_raw_clock / (ClkMHz * __MHZ);
|
||||
if(adc_clock_div < 1)
|
||||
return ERROR;
|
||||
|
||||
RCU_ADCClkConfig(ClkSrc, 7, ENABLE); //12.5MHz
|
||||
RCU_ADCClkCmd(ENABLE);
|
||||
/* Настройка источника тактирования и делителя */
|
||||
RCU_ADCClkConfig(ClkSrc, (uint32_t)(adc_clock_div - 1), ENABLE);
|
||||
|
||||
/* Включение тактирования, если запрошено */
|
||||
if(state == ENABLE)
|
||||
{
|
||||
RCU_ADCClkCmd(ENABLE);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инкремент счетчика миллисекунд.
|
||||
*/
|
||||
static inline void millis_inc(void)
|
||||
{
|
||||
msTick+=msTickInc;
|
||||
}
|
||||
/**
|
||||
* @brief Инкремент счетчика микросекунд.
|
||||
*/
|
||||
static inline void micros_inc(void)
|
||||
{
|
||||
usTick+=usTickInc;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
/*==============================================================================
|
||||
* Инициализация тактирования с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sysclk.h
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер тактирования системы на основе PLIB035.
|
||||
* Данный файл содержит определения типов, структур и прототипы функций
|
||||
* для работы с системным тактированием, включая:
|
||||
* + Типы системных тиков
|
||||
* + Структуру для управления коллбеками
|
||||
* + Прототипы функций для инициализации тактирования
|
||||
* + Функции настройки тактирования периферии
|
||||
* + Функции работы со временем
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __RCU_H
|
||||
#define __RCU_H
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
@@ -13,18 +21,58 @@
|
||||
#include "retarget_conf.h"
|
||||
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
extern __IO uint32_t uwTick;
|
||||
|
||||
/** @brief Конвертация МГц в Гц */
|
||||
#define __MHZ 1000000
|
||||
|
||||
/** @brief Максимальное количество коллбеков */
|
||||
#define SYSCLK_NUMB_OF_CUSTOM_CALLBACKS 16
|
||||
|
||||
|
||||
//-- Exported variables --------------------------------------------------------
|
||||
extern __IO uint32_t msTick;
|
||||
extern __IO uint32_t usTick;
|
||||
|
||||
//-- Types ---------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Типы частот системных тиков
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SYSCLK_Tick_1us = 1000000, /**< Тик 1 микросекунда */
|
||||
SYSCLK_Tick_10us = 100000, /**< Тик 10 микросекунд */
|
||||
SYSCLK_Tick_100us = 10000, /**< Тик 100 микросекунд */
|
||||
SYSCLK_Tick_1ms = 1000, /**< Тик 1 миллисекунда */
|
||||
SYSCLK_Tick_10ms = 100, /**< Тик 10 миллисекунд */
|
||||
SYSCLK_Tick_100ms = 10, /**< Тик 100 миллисекунд */
|
||||
}SYSCLK_TickHz_TypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура для управления системными коллбеками
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int CallbackInUse; /**< Количество активных коллбеков */
|
||||
void (*Callback[SYSCLK_NUMB_OF_CUSTOM_CALLBACKS])(void); /**< Массив указателей на функции-коллбеки */
|
||||
uint32_t CallbackPeriod[SYSCLK_NUMB_OF_CUSTOM_CALLBACKS]; /**< Периоды вызова коллбеков в мс */
|
||||
uint32_t CallbackPrevMs[SYSCLK_NUMB_OF_CUSTOM_CALLBACKS]; /**< Время последнего вызова коллбеков */
|
||||
} SYSCLK_CallbackHandleTypeDef;
|
||||
|
||||
|
||||
//-- Exported functions prototypes ---------------------------------------------
|
||||
/* Инициализация системного тактирования */
|
||||
void sysclk_init(void);
|
||||
/* Общий обработчик прерываний SysClock */
|
||||
void sysclk_irq_handler(void);
|
||||
|
||||
/* Добавление периодического коллбека */
|
||||
OperationStatus SYSCLK_Set_Callback(void (*Callback)(void), uint32_t PeriodInMs);
|
||||
|
||||
/* Получение текущего времени в миллисекундах */
|
||||
uint32_t millis(void);
|
||||
void millis_inc(void);
|
||||
/* Получение текущего времени в микросекундах */
|
||||
uint32_t micros(void);
|
||||
void micros_inc(void);
|
||||
|
||||
|
||||
|
||||
/* Настройка тактирования АЦП */
|
||||
OperationStatus rcu_set_clock_adc(RCU_PeriphClk_TypeDef ClkSrc, float ClkMHz, FunctionalState state);
|
||||
#endif /*__RCU_H*/
|
||||
|
||||
177
Core/App/tmr.c
177
Core/App/tmr.c
@@ -1,22 +1,85 @@
|
||||
/*==============================================================================
|
||||
* Инициализация таймеров с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file tmr.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер таймеров на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию таймеров TMR0-TMR3
|
||||
* + Запуск и остановку таймера
|
||||
* + Блокирующие и неблокирующие задержки
|
||||
* + Настройку callback-функций
|
||||
* + Общий обработчик прерываний таймера
|
||||
* + Псевдо-PLIB функции для инициализации таймеров
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены конфигурационные структуры tmrx_config в periph_config.h
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка периферии (periph_config.h):
|
||||
(+) Определить структуры TMR_ExtInit_TypeDef для нужных таймеров:
|
||||
tmr0_config, tmr1_config, tmr2_config, tmr3_config
|
||||
(+) Настроить частоту/период в мкс или тиках, прескалер
|
||||
(+) Разрешить прерывания (IT) и при необходимости ADC SOC / DMA запросы
|
||||
(+) Указать внешнее тактирование при необходимости
|
||||
(+) Установить callback-функцию (можно NULL)
|
||||
|
||||
2. Инициализация таймеров:
|
||||
(+) tmr_init_first() — первичная настройка тактирования, сброс периферии и NVIC
|
||||
(+) tmr_init(&htmr, &config) — инициализация конкретного таймера с конфигурацией
|
||||
|
||||
3. Callback-функции (опционально):
|
||||
(+) TMR_Set_Callback(&htmr, TMR_Callback_Update, Callback)
|
||||
|
||||
4. Запуск и остановка таймера:
|
||||
(+) TMR_Start(&htmr) — запуск таймера
|
||||
(+) TMR_Stop(&htmr) — остановка таймера
|
||||
|
||||
5. Задержки:
|
||||
- Blocking (блокирующая):
|
||||
(+) TMR_Delay(&htmr, ticks) — задержка в тиках таймера
|
||||
- Non-blocking (неблокирующая):
|
||||
(+) TMR_Delay_Start(&htmr, &var) — запоминает текущее значение таймера
|
||||
(+) TMR_Delay_Done(&htmr, ticks, &var) — проверяет завершение задержки
|
||||
|
||||
6. Получение текущих значений:
|
||||
(+) TMR_Get_Cnt(&htmr) — получение текущего счетчика с учетом псевдопрескалера
|
||||
(+) TMR_Get_Period(&htmr) — получение периода таймера с учетом псевдопрескалера
|
||||
|
||||
7. Обработка прерываний:
|
||||
(+) tmr_irq_handler(&htmr) — общий обработчик ISR
|
||||
- В обработчиках автоматически вызываются соответствующие callback-функции
|
||||
и сбрасываются флаги
|
||||
|
||||
8. Псевдо-PLIB функции:
|
||||
(+) TMR_Init(TMRx, InitStruct) — инициализация таймера с расширенными параметрами
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "periph_config.h"
|
||||
|
||||
TMR_HandleTypeDef htmr0;
|
||||
TMR_HandleTypeDef htmr1;
|
||||
TMR_HandleTypeDef htmr2;
|
||||
TMR_HandleTypeDef htmr3;
|
||||
TMR_HandleTypeDef htmr0; /*!< Хендл TMR0 */
|
||||
TMR_HandleTypeDef htmr1; /*!< Хендл TMR1 */
|
||||
TMR_HandleTypeDef htmr2; /*!< Хендл TMR2 */
|
||||
TMR_HandleTypeDef htmr3; /*!< Хендл TMR3 */
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
//-- TMR Init functions --------------------------------------------------------
|
||||
/**
|
||||
* @brief Первичная инициализация таймеров TMR0-TMR3
|
||||
* @details Настройка таймеров и хендлов: тактирование, прерывания
|
||||
*/
|
||||
void tmr_init_first(void)
|
||||
{
|
||||
#if (USE_TMR0==1)
|
||||
@@ -97,32 +160,43 @@ OperationStatus tmr_init(TMR_HandleTypeDef *htmr, TMR_ExtInit_TypeDef *NewConfig
|
||||
/**
|
||||
* @brief Установка коллбека таймера
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @param cb_type Тип коллбека
|
||||
* @param Callback Функция коллбека
|
||||
* @param CallbackType Тип коллбека
|
||||
* @param UpdCallback Функция коллбека
|
||||
* @retval void
|
||||
*/
|
||||
OperationStatus tmr_set_callback(TMR_HandleTypeDef* htmr, int cb_type, void (*Callback)(void))
|
||||
OperationStatus TMR_Set_Callback(TMR_HandleTypeDef* htmr, TMR_CallbackTypeDef CallbackType, void (*Callback)(void))
|
||||
{
|
||||
if(!htmr || !htmr->Instance || !htmr->Config)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
htmr->Config->Callback = Callback;
|
||||
|
||||
|
||||
switch(CallbackType)
|
||||
{
|
||||
case TMR_Callback_Update:
|
||||
htmr->Config->UpdCallback = Callback;
|
||||
break;
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-- TMR API functions --------------------------------------------------------
|
||||
/**
|
||||
* @brief Запуск таймера
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
*/
|
||||
OperationStatus tmr_start(TMR_HandleTypeDef *htmr)
|
||||
OperationStatus TMR_Start(TMR_HandleTypeDef *htmr, FunctionalState IT)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
TMR_ITCmd(htmr->Instance, IT);
|
||||
TMR_Cmd(htmr->Instance, ENABLE);
|
||||
|
||||
return OK;
|
||||
@@ -133,17 +207,59 @@ OperationStatus tmr_start(TMR_HandleTypeDef *htmr)
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
*/
|
||||
OperationStatus tmr_stop(TMR_HandleTypeDef *htmr)
|
||||
OperationStatus TMR_Stop(TMR_HandleTypeDef *htmr, FunctionalState IT)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
TMR_ITCmd(htmr->Instance, IT);
|
||||
TMR_Cmd(htmr->Instance, DISABLE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить счетчик таймера (с псевдопрескалером)
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @retval Текущие значение счетчика с псевдопрескалером
|
||||
* @details Если частота таймера 100 МГц, и псведопрескалер 100-1,
|
||||
* то при реальном счетчике 100,000, вернется значение 1,000
|
||||
*/
|
||||
uint32_t TMR_Get_Cnt(TMR_HandleTypeDef *htmr)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
uint32_t presc = htmr->Config->Prescaler+1;
|
||||
uint32_t currtick = htmr->Instance->VALUE;
|
||||
|
||||
return currtick/presc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить период таймера (с псевдопрескалером)
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @retval Период с псевдопрескалером
|
||||
* @details Если частота таймера 100 МГц, и псведопрескалер 100-1, и период равен 1 мс,
|
||||
* то при реальном периоде 100,000, вернется значение 1,000
|
||||
*/
|
||||
uint32_t TMR_Get_Period(TMR_HandleTypeDef *htmr)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
uint32_t presc = htmr->Config->Prescaler+1;
|
||||
uint32_t currload = htmr->Instance->LOAD;
|
||||
|
||||
return currload/presc;
|
||||
}
|
||||
//-- TMR Delays API functions -------------------------------------------------
|
||||
/**
|
||||
* @brief Задержка в тиках таймера (блокирующая).
|
||||
* @param htmr Указатель на хендл таймера.
|
||||
@@ -151,7 +267,7 @@ OperationStatus tmr_stop(TMR_HandleTypeDef *htmr)
|
||||
* @return OperationStatus.
|
||||
* @details Формирует задержку с блокировкой программы.
|
||||
*/
|
||||
OperationStatus tmr_delay(TMR_HandleTypeDef *htmr, uint32_t delay)
|
||||
OperationStatus TMR_Delay(TMR_HandleTypeDef *htmr, uint32_t delay)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
return ERROR;
|
||||
@@ -183,9 +299,11 @@ OperationStatus tmr_delay(TMR_HandleTypeDef *htmr, uint32_t delay)
|
||||
* @param var Указатель на переменную куда положить значение тиков.
|
||||
* @return OperationStatus.
|
||||
* @details Запоминает счетчик для начала отсчета неблокирующей задержки.
|
||||
* @ref tmr_delay_done для проверки статуса задержки
|
||||
* @ref TMR_Delay_Done для проверки статуса задержки.
|
||||
* @note Переменная содержит сырые тики, без преобразования под псевдопрескалер,
|
||||
* поэтому в var могут быть неадекватно большие значения тиков
|
||||
*/
|
||||
OperationStatus tmr_delay_start(TMR_HandleTypeDef *htmr, uint32_t *var)
|
||||
OperationStatus TMR_Delay_Start(TMR_HandleTypeDef *htmr, uint32_t *var)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
return ERROR;
|
||||
@@ -202,9 +320,11 @@ OperationStatus tmr_delay_start(TMR_HandleTypeDef *htmr, uint32_t *var)
|
||||
* @param var Указатель на переменную где хранится тики в момент начала задержки.
|
||||
* @return 1 - задержка прошла. 0 - задержка в процессе.
|
||||
* @details Формирует задержку с блокировкой программы.
|
||||
* Перед ожиданием задержки надо инициализировать задержку @ref tmr_delay_start
|
||||
* Перед ожиданием задержки надо инициализировать задержку @ref TMR_Delay_Start
|
||||
* @note Функция считает задержку через сырые тики, поэтому в var могут быть
|
||||
* неадекватно большие значения тиков
|
||||
*/
|
||||
int tmr_delay_done(TMR_HandleTypeDef *htmr, uint32_t delay, uint32_t *var)
|
||||
int TMR_Delay_Done(TMR_HandleTypeDef *htmr, uint32_t delay, uint32_t *var)
|
||||
{
|
||||
if(!htmr || !htmr->Instance)
|
||||
return 0;
|
||||
@@ -232,13 +352,14 @@ int tmr_delay_done(TMR_HandleTypeDef *htmr, uint32_t delay, uint32_t *var)
|
||||
}
|
||||
|
||||
|
||||
//-- TMR Handler functions ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Обработчик прерывания таймера
|
||||
* @param htmr указатель на хендл таймера
|
||||
* @retval void
|
||||
*/
|
||||
void tmr_handler(TMR_HandleTypeDef* htmr)
|
||||
void tmr_irq_handler(TMR_HandleTypeDef* htmr)
|
||||
{
|
||||
if((htmr->Instance == NULL) || (htmr->Config == NULL))
|
||||
{
|
||||
@@ -249,8 +370,8 @@ void tmr_handler(TMR_HandleTypeDef* htmr)
|
||||
if (TMR_ITStatus(htmr->Instance) == SET)
|
||||
{
|
||||
/* Если есть коллбек вызываем его */
|
||||
if(htmr->Config->Callback)
|
||||
htmr->Config->Callback();
|
||||
if(htmr->Config->UpdCallback)
|
||||
htmr->Config->UpdCallback();
|
||||
|
||||
/* Очистка флага прерывания */
|
||||
TMR_ITStatusClear(htmr->Instance);
|
||||
@@ -258,7 +379,7 @@ void tmr_handler(TMR_HandleTypeDef* htmr)
|
||||
}
|
||||
|
||||
|
||||
/* Расширение библиотеки plib */
|
||||
//-- TMR pseudoPLIB functions -------------------------------------------------
|
||||
/**
|
||||
* @brief Инициализирует модуль TMRx согласно параметрам структуры InitStruct.
|
||||
* @param TMRx Выбор таймера, где x=A|B
|
||||
|
||||
120
Core/App/tmr.h
120
Core/App/tmr.h
@@ -1,11 +1,16 @@
|
||||
/*==============================================================================
|
||||
* Инициализация таймеров с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file tmr.h
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер UART на основе PLIB035.
|
||||
* Данный файл содержит определения типов, структур и прототипы функций
|
||||
* для работы с TMR, включая:
|
||||
* + Структуры и typedef для таймеров
|
||||
* + Макросы для конфигурации периодов и частот
|
||||
* + Прототипы функций для инициализации и API драйвера
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef __TMR_H
|
||||
#define __TMR_H
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
@@ -13,51 +18,94 @@
|
||||
#include "retarget_conf.h"
|
||||
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
// Дефайны для режима таймера Период в мкс, Частота, ПсевдоПрескалер, Период в тиках
|
||||
#define PERIOD_MKS(_per_) _per_, 0, 0, 0
|
||||
#define FREQ_HZ(_freq_) 0, _freq_, 0, 0
|
||||
#define LOAD(_load_, _presc_) 0, 0, _presc_, _load_
|
||||
// Дефайны для режима таймера Период в мкс, Частота, ПсевдоПрескалер, Период в тиках
|
||||
/** @brief Период в мкс */
|
||||
#define PERIOD_MKS(_per_) (_per_), 0, 0, 0
|
||||
/** @brief Период в Гц */
|
||||
#define FREQ_HZ(_freq_) 0, (_freq_), 0, 0
|
||||
/** @brief Период в прескалере и тиках */
|
||||
#define LOAD(_load_, _presc_) 0, 0, (_presc_), (_load_)
|
||||
|
||||
//-- Types ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Типы callback-функций TMR
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TMR_Callback_Update, /*!< Переполнение (опустошение) таймера */
|
||||
} TMR_CallbackTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Расширенная конфигурация таймера
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float ClkFreq; /*!< Частота тактирования таймера в МГц */
|
||||
float ClkFreq; /*!< Частота тактирования таймера в МГц */
|
||||
|
||||
uint32_t PeriodUs; /*!< Период таймера в мкс */
|
||||
uint32_t FreqHz; /*!< Частота таймера в Гц */
|
||||
uint32_t Prescaler; /*!< Псевдопрескалер частоты */
|
||||
uint32_t Load; /*!< Период таймера в тиках */
|
||||
uint32_t PeriodUs; /*!< Период таймера в мкс */
|
||||
uint32_t FreqHz; /*!< Частота таймера в Гц */
|
||||
uint32_t Prescaler; /*!< Псевдопрескалер */
|
||||
uint32_t Load; /*!< Период таймера в тиках */
|
||||
|
||||
FunctionalState IT; /*!< Разрешение работы прерывания */
|
||||
FunctionalState ADCSOC; /*!< Разрешение генерации сигналов запуска АЦП */
|
||||
FunctionalState DMAReq; /*!< Разрешение генерации запросов к DMA */
|
||||
FunctionalState IT; /*!< Разрешение прерывания */
|
||||
FunctionalState ADCSOC; /*!< Разрешение генерации запуска АЦП */
|
||||
FunctionalState DMAReq; /*!< Разрешение генерации DMA-запросов */
|
||||
TMR_ExtInput_TypeDef ExtInput; /*!< Настройка внешнего тактирования таймера */
|
||||
void (*Callback)(void); /* Коллбек который вызовется по прерыванию таймера */
|
||||
}TMR_ExtInit_TypeDef;
|
||||
|
||||
void (*UpdCallback)(void); /*!< Callback-функция по прерыванию таймера */
|
||||
} TMR_ExtInit_TypeDef;
|
||||
|
||||
/**
|
||||
* @brief Хендл таймера
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
TMR_TypeDef *Instance;
|
||||
TMR_ExtInit_TypeDef *Config;
|
||||
}TMR_HandleTypeDef;
|
||||
TMR_TypeDef *Instance; /*!< Указатель на регистры таймера */
|
||||
TMR_ExtInit_TypeDef *Config; /*!< Конфигурация таймера */
|
||||
} TMR_HandleTypeDef;
|
||||
|
||||
//-- External handles ----------------------------------------------------------
|
||||
extern TMR_HandleTypeDef htmr0;
|
||||
extern TMR_HandleTypeDef htmr1;
|
||||
extern TMR_HandleTypeDef htmr2;
|
||||
extern TMR_HandleTypeDef htmr3;
|
||||
|
||||
//-- Exported functions prototypes ---------------------------------------------
|
||||
|
||||
/* Init functions */
|
||||
|
||||
/* Первичная инициализация таймеров */
|
||||
void tmr_init_first(void);
|
||||
|
||||
/* Общий обработчик прерывания таймера */
|
||||
void tmr_irq_handler(TMR_HandleTypeDef* htmr);
|
||||
/* Инициализация TMRx */
|
||||
OperationStatus tmr_init(TMR_HandleTypeDef *htmr, TMR_ExtInit_TypeDef *NewConfig);
|
||||
OperationStatus tmr_set_callback(TMR_HandleTypeDef* htmr, int cb_type, void (*Callback)(void));
|
||||
|
||||
OperationStatus tmr_start(TMR_HandleTypeDef *htmr);
|
||||
OperationStatus tmr_stop(TMR_HandleTypeDef *htmr);
|
||||
OperationStatus tmr_delay(TMR_HandleTypeDef *htmr, uint32_t delay);
|
||||
OperationStatus tmr_delay_start(TMR_HandleTypeDef *htmr, uint32_t *var);
|
||||
int tmr_delay_done(TMR_HandleTypeDef *htmr, uint32_t delay, uint32_t *var);
|
||||
|
||||
|
||||
void tmr_handler(TMR_HandleTypeDef* htmr);
|
||||
/* Инициализация таймера (её нет в PLIB, поэтому она здесь) */
|
||||
void TMR_Init(TMR_TypeDef* TMRx, TMR_ExtInit_TypeDef* InitStruct);
|
||||
|
||||
/* Установка callback-функции таймера */
|
||||
OperationStatus TMR_Set_Callback(TMR_HandleTypeDef* htmr, TMR_CallbackTypeDef CallbackType, void (*Callback)(void));
|
||||
|
||||
|
||||
|
||||
/* API functions*/
|
||||
|
||||
/* Запуск таймера */
|
||||
OperationStatus TMR_Start(TMR_HandleTypeDef *htmr, FunctionalState IT);
|
||||
/* Остановка таймера */
|
||||
OperationStatus TMR_Stop(TMR_HandleTypeDef *htmr, FunctionalState IT);
|
||||
/*Получить счетчик таймера (с псевдопрескалером) */
|
||||
uint32_t TMR_Get_Cnt(TMR_HandleTypeDef *htmr);
|
||||
/* Получить период таймера (с псевдопрескалером) */
|
||||
uint32_t TMR_Get_Period(TMR_HandleTypeDef *htmr);
|
||||
|
||||
/* Задержка в тиках таймера (блокирующая). */
|
||||
OperationStatus TMR_Delay(TMR_HandleTypeDef *htmr, uint32_t delay);
|
||||
/* Проверка завершения неблокирующей задержки. */
|
||||
OperationStatus TMR_Delay_Start(TMR_HandleTypeDef *htmr, uint32_t *var);
|
||||
/* Проверка завершения неблокирующей задержки. */
|
||||
int TMR_Delay_Done(TMR_HandleTypeDef *htmr, uint32_t delay, uint32_t *var);
|
||||
|
||||
|
||||
#endif /*__TMR_H*/
|
||||
|
||||
377
Core/App/uart.c
377
Core/App/uart.c
@@ -1,28 +1,105 @@
|
||||
/*==============================================================================
|
||||
* Инициализация Instance с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file uart.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер UART на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию UART0/UART1
|
||||
* + Управление FIFO
|
||||
* + Передачу и приём данных в blocking и interrupt режимах
|
||||
* + Общий обработчик прерываний UART
|
||||
* + Функции настройки GPIO для UART
|
||||
* + Очередь передачи для предотвращения потери данных
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены конфигурационные структуры uartx_config в periph_config.h
|
||||
* - Определены пины TX/RX для UART0/UART1
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка периферии (periph_config.h):
|
||||
(+) Определить структуры UART_ExtInit_TypeDef для нужных UART:
|
||||
uart0_config, uart1_config
|
||||
(+) Настроить скорость, стоп-биты, четность, длину данных
|
||||
(+) Настроить FIFO и направление (Tx, Rx или оба)
|
||||
(+) Определить callback-функции (можно NULL)
|
||||
(+) Определить пины TX/RX для UART0/UART1
|
||||
(+) Включить/отключить очередь сообщений для отправки: USE_TX_QUEUE в uart.h
|
||||
|
||||
2. Инициализация UART:
|
||||
(+) uart_init_first() — первичная настройка GPIO, тактирования и NVIC
|
||||
(+) uart_init(&huart, &config) — инициализация конкретного UART с конфигурацией
|
||||
|
||||
3. Callback-функции:
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Rx, Callback) — вызов при приёме данных
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Tx, Callback) — вызов при завершении передачи
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Idle, Callback) — вызов при событии Idle
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Error, Callback) — вызов при ошибках
|
||||
|
||||
4. Запуск UART и FIFO:
|
||||
(+) UART_Start(&huart, TxFifoLevel, RxFifoLevel) — включает UART и настраивает FIFO
|
||||
|
||||
5. Передача и приём данных:
|
||||
- Режим Polling (blocking):
|
||||
(+) UART_Transmit(&huart, buf, size, timeout) — передача данных с ожиданием
|
||||
(+) UART_Receive(&huart, buf, size, timeout) — приём данных с ожиданием
|
||||
- Режим Interrupt (non-blocking):
|
||||
(+) UART_Transmit_IT(&huart, buf, size) — передача данных через прерывания
|
||||
(+) UART_Receive_IT(&huart, buf, size) — приём данных через прерывания
|
||||
|
||||
6. Обработка прерываний UART:
|
||||
(+) uart_irq_handler(&huart) — общий обработчик ISR для RX/TX FIFO, ошибок и Idle
|
||||
- В обработчиках автоматически вызываются соответствующие callback-функции
|
||||
и сбрасываются флаги
|
||||
- Поддерживается очередь передачи для предотвращения потери данных
|
||||
|
||||
7. GPIO для UART:
|
||||
(+) uart0_gpio_init()/uart0_gpio_deinit() — инициализация и деинициализация UART0
|
||||
(+) uart1_gpio_init()/uart1_gpio_deinit() — инициализация и деинициализация UART1
|
||||
|
||||
8. Режимы работы:
|
||||
(+) Polling (blocking) — функции блокируются до завершения передачи/приёма
|
||||
(+) Interrupt (non-blocking) — передача/приём через прерывания, управление через callback
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "periph_config.h"
|
||||
|
||||
UART_HandleTypeDef huart0;
|
||||
UART_HandleTypeDef huart1;
|
||||
|
||||
UART_HandleTypeDef huart0; /*!< Хендл UART0 */
|
||||
UART_HandleTypeDef huart1; /*!< Хендл UART1 */
|
||||
|
||||
|
||||
//-- Private function prototypes -----------------------------------------------
|
||||
static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode);
|
||||
static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode);
|
||||
#if USE_TX_QUEUE==1
|
||||
static void __uart_tx_queue_process(UART_HandleTypeDef *huart);
|
||||
static OperationStatus __uart_tx_queue_push(UART_HandleTypeDef *huart, const uint8_t *buf, uint16_t size);
|
||||
static OperationStatus __uart_tx_queue_pop(UART_HandleTypeDef *huart);
|
||||
#endif
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//-- Peripheral init functions -------------------------------------------------
|
||||
//-- UART Init functions -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Первичная инициализация UART (UART0 / UART1)
|
||||
* @details Настройка UART и хендлов: GPIO, тактирование и прерывания
|
||||
*/
|
||||
void uart_init_first(void)
|
||||
{
|
||||
|
||||
@@ -68,9 +145,9 @@ void uart_init_first(void)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация Instance
|
||||
* @param htmr указатель на хендл Instance
|
||||
* @param NewConfig указатель на новую конфигурацию Instance, иначе используется та, что в структуре
|
||||
* @brief Инициализация UART
|
||||
* @param htmr указатель на хендл UART
|
||||
* @param NewConfig указатель на новую конфигурацию UART, иначе используется та, что в структуре
|
||||
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
|
||||
*/
|
||||
OperationStatus uart_init(UART_HandleTypeDef *huart, UART_ExtInit_TypeDef *NewConfig)
|
||||
@@ -92,7 +169,52 @@ OperationStatus uart_init(UART_HandleTypeDef *huart, UART_ExtInit_TypeDef *NewCo
|
||||
return OK;
|
||||
}
|
||||
|
||||
OperationStatus uart_start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Установка коллбека UART
|
||||
* @param htmr указатель на хендл UART
|
||||
* @param CallbackType Тип коллбека
|
||||
* @param Callback Функция коллбека
|
||||
* @retval void
|
||||
*/
|
||||
OperationStatus UART_Set_Callback(UART_HandleTypeDef* huart, UART_CallbackTypeDef CallbackType, void (*Callback)(void))
|
||||
{
|
||||
if (!huart || !huart->Instance || !huart->Config)
|
||||
return ERROR;
|
||||
|
||||
switch(CallbackType)
|
||||
{
|
||||
case UART_Callback_Rx:
|
||||
huart->Config->RxCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Tx:
|
||||
huart->Config->TxCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Idle:
|
||||
huart->Config->IdleCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Error:
|
||||
huart->Config->ErrCallback = Callback;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
//-- UART API functions --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Запуск UART и инициализация FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param TxFifoLevel уровень прерывания TX FIFO
|
||||
* @param RxFifoLevel уровень прерывания RX FIFO
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке
|
||||
*/
|
||||
OperationStatus UART_Start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel)
|
||||
{
|
||||
if (!huart)
|
||||
return ERROR;
|
||||
@@ -111,12 +233,36 @@ OperationStatus uart_start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxF
|
||||
huart->RxSize = 0;
|
||||
huart->RxBusy = 0;
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
huart->TxQueue.QueueHead = 0;
|
||||
huart->TxQueue.QueueTail = 0;
|
||||
huart->TxQueue.QueueCount = 0;
|
||||
huart->TxQueue.QueueEmpty = 1;
|
||||
huart->TxQueue.QueueFull = 0;
|
||||
|
||||
for (uint8_t i = 0; i < TX_QUEUE_SIZE; i++)
|
||||
{
|
||||
huart->TxQueue.Queue[i].Buf = NULL;
|
||||
huart->TxQueue.Queue[i].Size = 0;
|
||||
huart->TxQueue.Queue[i].InUse = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
UART_Cmd(huart->Instance, ENABLE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
OperationStatus uart_transmit(UART_HandleTypeDef *huart,
|
||||
/**
|
||||
* @brief Передача данных по UART (блокирующий режим)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер данных
|
||||
* @param size размер данных в байтах
|
||||
* @param timeout таймаут ожидания (мс)
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
|
||||
*/
|
||||
OperationStatus UART_Transmit(UART_HandleTypeDef *huart,
|
||||
uint8_t *buf,
|
||||
uint16_t size,
|
||||
uint32_t timeout)
|
||||
@@ -143,8 +289,15 @@ OperationStatus uart_transmit(UART_HandleTypeDef *huart,
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
OperationStatus uart_receive(UART_HandleTypeDef *huart,
|
||||
/**
|
||||
* @brief Приём данных по UART (блокирующий режим)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер приёма
|
||||
* @param size количество принимаемых байт
|
||||
* @param timeout таймаут ожидания (мс)
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
|
||||
*/
|
||||
OperationStatus UART_Receive(UART_HandleTypeDef *huart,
|
||||
uint8_t *buf,
|
||||
uint16_t size,
|
||||
uint32_t timeout)
|
||||
@@ -172,14 +325,37 @@ OperationStatus uart_receive(UART_HandleTypeDef *huart,
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
OperationStatus uart_transmit_it(UART_HandleTypeDef *huart,
|
||||
/**
|
||||
* @brief Передача данных по UART (прерывания)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер данных
|
||||
* @param size размер данных в байтах
|
||||
* @retval OperationStatus OK - если успешно, ERROR - если передача уже идёт
|
||||
*/
|
||||
OperationStatus UART_Transmit_IT(UART_HandleTypeDef *huart,
|
||||
uint8_t *buf,
|
||||
uint16_t size)
|
||||
{
|
||||
if (!huart || !buf || size == 0)
|
||||
return ERROR;
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
// Автоматически используем очередь
|
||||
if (huart->TxQueue.QueueFull)
|
||||
return ERROR;
|
||||
|
||||
OperationStatus status = __uart_tx_queue_push(huart, buf, size);
|
||||
if (status != OK)
|
||||
return ERROR;
|
||||
|
||||
if (!huart->TxBusy)
|
||||
{
|
||||
__uart_tx_queue_process(huart);
|
||||
}
|
||||
|
||||
return OK;
|
||||
#else
|
||||
// Без очереди
|
||||
// Если TX занят, возвращаем ERROR
|
||||
if (huart->TxBusy)
|
||||
return ERROR;
|
||||
@@ -195,11 +371,17 @@ OperationStatus uart_transmit_it(UART_HandleTypeDef *huart,
|
||||
__uart_fifo_transmit(huart, 1);
|
||||
|
||||
return OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
OperationStatus uart_receive_it(UART_HandleTypeDef *huart,
|
||||
/**
|
||||
* @brief Приём данных по UART (прерывания)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер приёма
|
||||
* @param size количество принимаемых байт
|
||||
* @retval OperationStatus OK - если успешно, ERROR - если приём уже идёт
|
||||
*/
|
||||
OperationStatus UART_Receive_IT(UART_HandleTypeDef *huart,
|
||||
uint8_t *buf,
|
||||
uint16_t size)
|
||||
{
|
||||
@@ -228,12 +410,20 @@ OperationStatus uart_receive_it(UART_HandleTypeDef *huart,
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
void uart_handler(UART_HandleTypeDef *huart)
|
||||
//-- UART Handler functions ---------------------------------------------------
|
||||
/**
|
||||
* @brief Общий обработчик прерываний UART
|
||||
* @param huart указатель на хендл UART
|
||||
* @details Обрабатывает RX/TX FIFO, ошибки и события Idle
|
||||
* @retval void
|
||||
*/
|
||||
void uart_irq_handler(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart || !huart->Instance || !huart->Config)
|
||||
return;
|
||||
|
||||
// GPIO_SetBits(GPIOA, GPIO_Pin_7);
|
||||
|
||||
UART_TypeDef *uart = huart->Instance;
|
||||
uint32_t mis = uart->MIS;
|
||||
|
||||
@@ -267,7 +457,7 @@ void uart_handler(UART_HandleTypeDef *huart)
|
||||
UART_ITStatusClear(uart, UART_ITSource_RecieveTimeout);
|
||||
|
||||
huart->RxBusy = 0;
|
||||
// Выключаем RX прерывания до следующего вызова uart_receive_it
|
||||
// Выключаем RX прерывания до следующего вызова UART_Receive_IT
|
||||
UART_ITCmd(uart,
|
||||
UART_ITSource_RxFIFOLevel |
|
||||
UART_ITSource_RecieveTimeout,
|
||||
@@ -287,6 +477,7 @@ void uart_handler(UART_HandleTypeDef *huart)
|
||||
|
||||
UART_ITStatusClear(uart, UART_ITSource_TxFIFOLevel);
|
||||
}
|
||||
|
||||
// Конец передачи
|
||||
if (mis & UART_ITSource_TransmitDone)
|
||||
{
|
||||
@@ -295,46 +486,23 @@ void uart_handler(UART_HandleTypeDef *huart)
|
||||
|
||||
if (huart->Config->TxCallback)
|
||||
huart->Config->TxCallback();
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
// Если есть очередь, обрабатываем следующий пакет
|
||||
__uart_tx_queue_process(huart);
|
||||
#endif
|
||||
|
||||
}
|
||||
// GPIO_ClearBits(GPIOA, GPIO_Pin_7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-- UART GPIO functions -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Установка коллбека Instance
|
||||
* @param htmr указатель на хендл Instance
|
||||
* @param cb_type Тип коллбека
|
||||
* @param Callback Функция коллбека
|
||||
* @retval void
|
||||
* @brief Инициализация GPIO для UART0
|
||||
*/
|
||||
OperationStatus uart_set_callback(UART_HandleTypeDef* huart, UART_CallbackTypeDef cb_type, void (*Callback)(void))
|
||||
{
|
||||
if (!huart || !huart->Instance || !huart->Config)
|
||||
return ERROR;
|
||||
|
||||
switch(cb_type)
|
||||
{
|
||||
case UART_Callback_Rx:
|
||||
huart->Config->RxCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Tx:
|
||||
huart->Config->TxCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Idle:
|
||||
huart->Config->IdleCallback = Callback;
|
||||
break;
|
||||
case UART_Callback_Error:
|
||||
huart->Config->ErrCallback = Callback;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
void uart0_gpio_init(void)
|
||||
{
|
||||
#if USE_UART0==1
|
||||
@@ -363,7 +531,9 @@ void uart0_gpio_init(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Деинициализация GPIO для UART0
|
||||
*/
|
||||
void uart0_gpio_deinit(void)
|
||||
{
|
||||
#if USE_UART0==1
|
||||
@@ -387,7 +557,9 @@ void uart0_gpio_deinit(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация GPIO для UART1
|
||||
*/
|
||||
void uart1_gpio_init(void)
|
||||
{
|
||||
#if USE_UART1==1
|
||||
@@ -417,7 +589,9 @@ void uart1_gpio_init(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Деинициализация GPIO для UART1
|
||||
*/
|
||||
void uart1_gpio_deinit(void)
|
||||
{
|
||||
#if USE_UART1==1
|
||||
@@ -442,7 +616,13 @@ void uart1_gpio_deinit(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-- UART private functions ----------------------------------------------------
|
||||
/**
|
||||
* @brief Приём данных из RX FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param it_mode режим работы (0 — polling, 1 — прерывания)
|
||||
* @retval int 1 — приём завершён, 0 — данные ещё принимаются
|
||||
*/
|
||||
static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
{
|
||||
while (!UART_FlagStatus(huart->Instance, UART_Flag_RxFIFOEmpty) &&
|
||||
@@ -470,6 +650,12 @@ static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Передача данных в TX FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param it_mode режим работы (0 — polling, 1 — прерывания)
|
||||
* @retval int 1 — передача завершена, 0 — данные ещё передаются
|
||||
*/
|
||||
static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
{
|
||||
while (!UART_FlagStatus(huart->Instance, UART_Flag_TxFIFOFull) &&
|
||||
@@ -499,4 +685,65 @@ static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
static void __uart_tx_queue_process(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart->TxBusy && !huart->TxQueue.QueueEmpty)
|
||||
{
|
||||
__uart_tx_queue_pop(huart);
|
||||
}
|
||||
}
|
||||
|
||||
static OperationStatus __uart_tx_queue_push(UART_HandleTypeDef *huart, const uint8_t *buf, uint16_t size)
|
||||
{
|
||||
if (!huart || !buf || size == 0 || huart->TxQueue.QueueFull)
|
||||
return ERROR;
|
||||
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].Buf = buf;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].Size = size;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].InUse = 1;
|
||||
|
||||
huart->TxQueue.QueueHead = (huart->TxQueue.QueueHead + 1) % TX_QUEUE_SIZE;
|
||||
huart->TxQueue.QueueCount++;
|
||||
|
||||
huart->TxQueue.QueueEmpty = 0;
|
||||
if (huart->TxQueue.QueueCount == TX_QUEUE_SIZE)
|
||||
huart->TxQueue.QueueFull = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
static OperationStatus __uart_tx_queue_pop(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart || huart->TxQueue.QueueEmpty)
|
||||
return ERROR;
|
||||
|
||||
const uint8_t *buf = huart->TxQueue.Queue[huart->TxQueue.QueueTail].Buf;
|
||||
uint16_t size = huart->TxQueue.Queue[huart->TxQueue.QueueTail].Size;
|
||||
|
||||
if (huart->TxBusy)
|
||||
return ERROR;
|
||||
|
||||
huart->TxBufPtr = buf;
|
||||
huart->TxSize = size;
|
||||
huart->TxCount = 0;
|
||||
huart->TxBusy = 1;
|
||||
|
||||
UART_ITCmd(huart->Instance, UART_ITSource_TxFIFOLevel, ENABLE);
|
||||
__uart_fifo_transmit(huart, 1);
|
||||
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].Buf = NULL;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].Size = 0;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].InUse = 0;
|
||||
|
||||
huart->TxQueue.QueueTail = (huart->TxQueue.QueueTail + 1) % TX_QUEUE_SIZE;
|
||||
huart->TxQueue.QueueCount--;
|
||||
|
||||
huart->TxQueue.QueueFull = 0;
|
||||
if (huart->TxQueue.QueueCount == 0)
|
||||
huart->TxQueue.QueueEmpty = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
186
Core/App/uart.h
186
Core/App/uart.h
@@ -1,11 +1,17 @@
|
||||
/*==============================================================================
|
||||
* Инициализация UART с использованием бибилотеки PLIB035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file uart.h
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер UART на основе PLIB035.
|
||||
* Данный файл содержит определения типов, структур и прототипы функций
|
||||
* для работы с UART, включая:
|
||||
* + Структуры и typedef для UART
|
||||
* + Макросы для конфигурации направления передачи
|
||||
* + Прототипы функций для инициализации и API драйвера
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __UART_H
|
||||
#define __UART_H
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
@@ -13,92 +19,148 @@
|
||||
#include "retarget_conf.h"
|
||||
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
// Дефайны для кольцевых буферов UART
|
||||
#ifndef UART_RX_BUF_SIZE
|
||||
#define UART_RX_BUF_SIZE 128
|
||||
#endif
|
||||
#ifndef UART_TX_BUF_SIZE
|
||||
#define UART_TX_BUF_SIZE 128
|
||||
#endif
|
||||
|
||||
// Дефайны для режима направления UART
|
||||
#define UART_Direction_None DISABLE, DISABLE
|
||||
#define UART_Direction_RxTx ENABLE, ENABLE
|
||||
#define UART_Direction_Tx DISABLE, ENABLE
|
||||
#define UART_Direction_Rx ENABLE, DISABLE
|
||||
// Дефайны для режима пина RxEnable, TxEnable
|
||||
/** @brief Направление: никакого */
|
||||
#define UART_Direction_None DISABLE, DISABLE
|
||||
/** @brief Направление: Rx и Tx */
|
||||
#define UART_Direction_RxTx ENABLE, ENABLE
|
||||
/** @brief Направление: только Tx */
|
||||
#define UART_Direction_Tx DISABLE, ENABLE
|
||||
/** @brief Направление: только Rx */
|
||||
#define UART_Direction_Rx ENABLE, DISABLE
|
||||
|
||||
// Дефайны для пинов UART
|
||||
#define UART0_Tx_Pin GPIO_Pin_10 // PB10 для UART0 Tx
|
||||
#define UART0_Rx_Pin GPIO_Pin_11 // PB11 для UART0 Rx
|
||||
#define UART0_GPIO_Port GPIOB
|
||||
#define UART0_Tx_Pin GPIO_Pin_10 /**< PB10 — UART0 Tx */
|
||||
#define UART0_Rx_Pin GPIO_Pin_1 /**< PB11 — UART0 Rx */
|
||||
#define UART0_GPIO_Port GPIOB /**< GPIO порт UART0 */
|
||||
|
||||
#define UART1_Tx_Pin GPIO_Pin_8 // PB8 для UART1 Tx
|
||||
#define UART1_Rx_Pin GPIO_Pin_9 // PB9 для UART1 Rx
|
||||
#define UART1_GPIO_Port GPIOB
|
||||
#define UART1_Tx_Pin GPIO_Pin_8 /**< PB8 — UART1 Tx */
|
||||
#define UART1_Rx_Pin GPIO_Pin_9 /**< PB9 — UART1 Rx */
|
||||
#define UART1_GPIO_Port GPIOB /**< GPIO порт UART1 */
|
||||
|
||||
#define USE_TX_QUEUE 1 /*!< Использовать очередь для отправки, чтобы не терять данные */
|
||||
#define TX_QUEUE_SIZE 32 /*!< Размер очереди в кол-ве буферов для отправки */
|
||||
|
||||
//-- Types ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Типы callback-функций UART
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
UART_Callback_Rx,
|
||||
UART_Callback_Tx,
|
||||
UART_Callback_Idle,
|
||||
UART_Callback_Error,
|
||||
}UART_CallbackTypeDef;
|
||||
UART_Callback_Rx, /*!< Приём данных завершён */
|
||||
UART_Callback_Tx, /*!< Передача данных завершена */
|
||||
UART_Callback_Idle, /*!< Обнаружено состояние IDLE */
|
||||
UART_Callback_Error, /*!< Ошибка UART */
|
||||
|
||||
} UART_CallbackTypeDef;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Расширенная конфигурация UART
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UART_Init_TypeDef UART_Init; /* Стандартная конфигурация из PLIB */
|
||||
|
||||
// Callback функции
|
||||
void (*RxCallback)(void); /* Вызывается при приеме полного сообщения */
|
||||
void (*TxCallback)(void); /* Вызывается при окончании передачи */
|
||||
void (*IdleCallback)(void); /* Вызывается при IDLE линии на RX */
|
||||
void (*ErrCallback)(void); /* Вызывается при ошибке */
|
||||
|
||||
UART_Init_TypeDef UART_Init; /*!< Стандартная конфигурация UART из PLIB */
|
||||
|
||||
/* Callback функции */
|
||||
void (*RxCallback)(void); /*!< Вызывается при приёме полного сообщения */
|
||||
void (*TxCallback)(void); /*!< Вызывается при окончании передачи */
|
||||
void (*IdleCallback)(void); /*!< Вызывается при IDLE линии RX */
|
||||
void (*ErrCallback)(void); /*!< Вызывается при ошибке UART */
|
||||
|
||||
} UART_ExtInit_TypeDef;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура элемента очереди
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t *Buf; /*!< Указатель на буфер данных */
|
||||
uint16_t Size; /*!< Размер данных в буфере */
|
||||
uint8_t InUse; /*!< Флаг занятости элемента */
|
||||
} UART_QueueItemTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура очереди UART
|
||||
*/
|
||||
typedef struct {
|
||||
UART_QueueItemTypeDef Queue[TX_QUEUE_SIZE]; /*!< Циклический буфер очереди */
|
||||
uint8_t QueueHead; /*!< Индекс головы очереди (куда добавляем) */
|
||||
uint8_t QueueTail; /*!< Индекс хвоста очереди (откуда берем) */
|
||||
uint8_t QueueCount; /*!< Количество элементов в очереди */
|
||||
uint8_t QueueEmpty; /*!< Флаг пустой очереди */
|
||||
uint8_t QueueFull; /*!< Флаг полной очереди */
|
||||
} UART_TxQueueTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Хендл UART
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UART_TypeDef *Instance; /* Регистры UART */
|
||||
UART_ExtInit_TypeDef *Config; /* Конфигурация UART */
|
||||
|
||||
UART_TypeDef *Instance; /*!< Регистры UART */
|
||||
UART_ExtInit_TypeDef *Config; /*!< Конфигурация UART */
|
||||
|
||||
/* ===== TX ===== */
|
||||
const uint8_t *TxBufPtr; /* текущий массив для передачи*/
|
||||
uint16_t TxCount; /* счетчик отправленых байт*/
|
||||
uint16_t TxSize; /* длина данных для отправки*/
|
||||
volatile uint8_t TxBusy; /* Флаг занятости TX*/
|
||||
const uint8_t *TxBufPtr; /*!< Указатель на буфер передачи */
|
||||
uint16_t TxCount; /*!< Счётчик переданных байт */
|
||||
uint16_t TxSize; /*!< Размер передаваемых данных */
|
||||
volatile uint8_t TxBusy; /*!< Флаг занятости TX */
|
||||
|
||||
/* ===== RX ===== */
|
||||
uint8_t *RxBufPtr; /* буфер для приёма*/
|
||||
uint16_t RxCount; /* счетчик принятых байт*/
|
||||
uint16_t RxSize; /* длина данных для приема*/
|
||||
volatile uint8_t RxBusy; /* Флаг занятости RX*/
|
||||
}UART_HandleTypeDef;
|
||||
uint8_t *RxBufPtr; /*!< Указатель на буфер приёма */
|
||||
uint16_t RxCount; /*!< Счётчик принятых байт */
|
||||
uint16_t RxSize; /*!< Размер принимаемых данных */
|
||||
volatile uint8_t RxBusy; /*!< Флаг занятости RX */
|
||||
|
||||
#if (USE_TX_QUEUE==1)
|
||||
/* == TX QUEUE == */
|
||||
UART_TxQueueTypeDef TxQueue;
|
||||
#endif
|
||||
|
||||
} UART_HandleTypeDef;
|
||||
|
||||
//-- External handles ----------------------------------------------------------
|
||||
|
||||
extern UART_HandleTypeDef huart0;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
|
||||
//-- Exported functions prototypes ---------------------------------------------
|
||||
|
||||
/* Init functions */
|
||||
|
||||
/* Первичная инициализация UART (UART0 / UART1) */
|
||||
void uart_init_first(void);
|
||||
|
||||
/* Инициализация UARTx */
|
||||
OperationStatus uart_init(UART_HandleTypeDef *huart, UART_ExtInit_TypeDef *NewConfig);
|
||||
OperationStatus uart_set_callback(UART_HandleTypeDef* huart, UART_CallbackTypeDef cb_type, void (*Callback)(void));
|
||||
OperationStatus uart_start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel);
|
||||
|
||||
OperationStatus uart_transmit(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout);
|
||||
OperationStatus uart_receive(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout);
|
||||
OperationStatus uart_transmit_it(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size);
|
||||
OperationStatus uart_receive_it(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size);
|
||||
|
||||
|
||||
void uart_handler(UART_HandleTypeDef *huart);
|
||||
/* Общий обработчик прерываний UART */
|
||||
void uart_irq_handler(UART_HandleTypeDef *huart);
|
||||
/* Инициализация GPIO для UART0 */
|
||||
void uart0_gpio_init(void);
|
||||
/* Деинициализация GPIO для UART0 */
|
||||
void uart0_gpio_deinit(void);
|
||||
/* Инициализация GPIO для UART1 */
|
||||
void uart1_gpio_init(void);
|
||||
/* Деинициализация GPIO для UART1 */
|
||||
void uart1_gpio_deinit(void);
|
||||
|
||||
/* API functions*/
|
||||
|
||||
/* Установка callback-функции UART */
|
||||
OperationStatus UART_Set_Callback(UART_HandleTypeDef *huart, UART_CallbackTypeDef CallbackType, void (*Callback)(void));
|
||||
/* Запуск UART и настройка FIFO */
|
||||
OperationStatus UART_Start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel);
|
||||
|
||||
/* Передача данных по UART (блокирующий режим) */
|
||||
OperationStatus UART_Transmit(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout);
|
||||
/* Приём данных по UART (блокирующий режим) */
|
||||
OperationStatus UART_Receive(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout);
|
||||
/* Передача данных по UART (режим прерываний) */
|
||||
OperationStatus UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size);
|
||||
/* Приём данных по UART (режим прерываний) */
|
||||
OperationStatus UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size);
|
||||
|
||||
|
||||
|
||||
#endif /*__UART_H*/
|
||||
|
||||
@@ -1,11 +1,59 @@
|
||||
/*==============================================================================
|
||||
* Прерывания микроконтроллера 1921ВК035
|
||||
*------------------------------------------------------------------------------
|
||||
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
|
||||
*==============================================================================
|
||||
* ЦНИИ СЭТ
|
||||
*==============================================================================
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file vk035_it.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Обработчики прерываний для микроконтроллера 1921ВК035.
|
||||
* Этот файл содержит:
|
||||
* + Обработчики прерываний периферии (UART, TMR, ADC, DMA и др.)
|
||||
* + Обработчики исключений Cortex-M4 (HardFault, SysTick и др.)
|
||||
* + Интеграцию с драйверами периферии через вызовы обработчиков
|
||||
* + Управление системным временем через SysTick
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого файла предполагает наличие корректных настроек:
|
||||
* - Определены USE_xxx макросы в periph_config.h для включения периферии
|
||||
* - Инициализированы соответствующие драйверы периферии
|
||||
* - Включены прерывания в NVIC через функции драйверов
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот файл #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка периферии (periph_config.h):
|
||||
(+) Определить USE_TMRx для используемых таймеров (0-3)
|
||||
(+) Определить USE_UARTx для используемых UART (0-1)
|
||||
(+) Определить USE_ADC_SEQx для используемых секвенсоров ADC (0-1)
|
||||
|
||||
2. Инициализация драйверов:
|
||||
(+) Вызвать функции инициализации драйверов (uart_init_first, tmr_init_first и т.д.)
|
||||
- Драйверы автоматически включат соответствующие прерывания в NVIC
|
||||
|
||||
3. Обработка прерываний:
|
||||
(+) Прерывания периферии автоматически перенаправляются в драйверы
|
||||
(+) Системные прерывания (SysTick) управляют временем millis/micros
|
||||
(+) Обработчики исключений обрабатывают критические ошибки
|
||||
|
||||
4. Интеграция с драйверами:
|
||||
(+) UART прерывания -> uart_irq_handler(&huartx)
|
||||
(+) TMR прерывания -> tmr_irq_handler(&htmrx)
|
||||
(+) ADC SEQ прерывания -> adc_seq_irq_handler(&hadc, SEQ_Num)
|
||||
|
||||
5. Системное время:
|
||||
(+) SysTick_Handler() автоматически обновляет millis() и micros()
|
||||
(+) Период SysTick настраивается в sysclk_init()
|
||||
|
||||
6. Особенности работы:
|
||||
(+) Неиспользуемые обработчики оставлены пустыми для будущего расширения
|
||||
(+) Критические ошибки (HardFault и др.) уходят в бесконечный цикл
|
||||
(+) Прерывания обрабатываются неблокирующе с минимальными задержками
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "main.h"
|
||||
@@ -15,60 +63,78 @@
|
||||
/* 1921VK035 Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/******************************************************************************/
|
||||
#if USE_WDT==1
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
void GPIOA_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
void GPIOB_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#if USE_TMR0==1
|
||||
void TMR0_IRQHandler(void)
|
||||
{
|
||||
tmr_handler(&htmr0);
|
||||
tmr_irq_handler(&htmr0);
|
||||
}
|
||||
#endif
|
||||
#if USE_TMR1==1
|
||||
void TMR1_IRQHandler(void)
|
||||
{
|
||||
tmr_handler(&htmr1);
|
||||
tmr_irq_handler(&htmr1);
|
||||
}
|
||||
#endif
|
||||
#if USE_TMR2==1
|
||||
void TMR2_IRQHandler(void)
|
||||
{
|
||||
tmr_handler(&htmr2);
|
||||
tmr_irq_handler(&htmr2);
|
||||
}
|
||||
#endif
|
||||
#if USE_TMR3==1
|
||||
void TMR3_IRQHandler(void)
|
||||
{
|
||||
tmr_handler(&htmr3);
|
||||
tmr_irq_handler(&htmr3);
|
||||
}
|
||||
#endif
|
||||
#if USE_UART0==1
|
||||
void UART0_TD_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart0);
|
||||
uart_irq_handler(&huart0);
|
||||
}
|
||||
void UART0_RX_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart0);
|
||||
uart_irq_handler(&huart0);
|
||||
}
|
||||
void UART0_TX_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart0);
|
||||
uart_irq_handler(&huart0);
|
||||
}
|
||||
void UART0_E_RT_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart0);
|
||||
uart_irq_handler(&huart0);
|
||||
}
|
||||
#endif
|
||||
#if USE_UART1==1
|
||||
void UART1_TD_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart1);
|
||||
uart_irq_handler(&huart1);
|
||||
}
|
||||
void UART1_RX_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart1);
|
||||
uart_irq_handler(&huart1);
|
||||
}
|
||||
void UART1_TX_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart1);
|
||||
uart_irq_handler(&huart1);
|
||||
}
|
||||
void UART1_E_RT_IRQHandler(void)
|
||||
{
|
||||
uart_handler(&huart1);
|
||||
uart_irq_handler(&huart1);
|
||||
}
|
||||
#endif
|
||||
#if USE_SPI==1
|
||||
void SPI_RO_RT_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -78,18 +144,28 @@ void SPI_RX_IRQHandler(void)
|
||||
void SPI_TX_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_I2C==1
|
||||
void I2C_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_ECAP0==1
|
||||
void ECAP0_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_ECAP1==1
|
||||
void ECAP1_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_ECAP2==1
|
||||
void ECAP2_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_PWM0==1
|
||||
void PWM0_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -99,6 +175,8 @@ void PWM0_HD_IRQHandler(void)
|
||||
void PWM0_TZ_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_PWM1==1
|
||||
void PWM1_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -108,6 +186,8 @@ void PWM1_HD_IRQHandler(void)
|
||||
void PWM1_TZ_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_PWM2==1
|
||||
void PWM2_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -117,20 +197,30 @@ void PWM2_HD_IRQHandler(void)
|
||||
void PWM2_TZ_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_QEP==1
|
||||
void QEP_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_ADC_SEQ0==1
|
||||
void ADC_SEQ0_IRQHandler(void)
|
||||
{
|
||||
adc_seq_handler(&hadc, ADC_SEQ_Num_0);
|
||||
adc_seq_irq_handler(&hadc, ADC_SEQ_Num_0);
|
||||
}
|
||||
#endif
|
||||
#if USE_ADC_SEQ1==1
|
||||
void ADC_SEQ1_IRQHandler(void)
|
||||
{
|
||||
adc_seq_handler(&hadc, ADC_SEQ_Num_1);
|
||||
adc_seq_irq_handler(&hadc, ADC_SEQ_Num_1);
|
||||
}
|
||||
#endif
|
||||
#if (USE_ADC_DC0==1) || (USE_ADC_DC1==1) || (USE_ADC_DC2==1) || (USE_ADC_DC3==1)
|
||||
void ADC_DC_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if USE_ADC_CAN==1
|
||||
void CAN0_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -179,9 +269,7 @@ void CAN14_IRQHandler(void)
|
||||
void CAN15_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
void FPU_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
void DMA_CH0_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
@@ -230,7 +318,7 @@ void DMA_CH14_IRQHandler(void)
|
||||
void DMA_CH15_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
void WDT_IRQHandler(void)
|
||||
void FPU_IRQHandler(void)
|
||||
{
|
||||
}
|
||||
void RCU_IRQHandler(void)
|
||||
@@ -320,5 +408,5 @@ void PendSV_Handler(void)
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
millis_inc();
|
||||
sysclk_irq_handler();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user