STM8S использование ADC или оцифровка аналоговых сигналов с использованием SPL а также примеры программ.
Ссылка на видео в YouTube До этой статьи мы работали с контроллерами только в цифровом формате теперь попробуем скрестить цифровой и аналоговый или получить цифровой вид из напряжения и конечно мы это сделаем с помощью ADC( аналого-цифровой преобразователь). Давайте посмотрим что из себя представляет этот ADC внутри контроллера.
Описание выводов принадлежащих ADC:
VDDA и VSSA-напряжение подаваемое на ADC относительно которого будут сниматься показания, по умолчанию подключают к питанию самого контроллера, эти выводы имеются не у всех контроллеров смотрите datasheet.
AIN0-AIN12-аналоговые порты или каналы подключаемые к ADC.
ADC_ETR-вход подачи внешнего сигнала для старта преобразования, также можно использовать внутренний от TIM1.
Периферия модуля ADC состоит из основных узлов это:
GPIO Ports-модуль для выбора подключаемого вывода к ядру ADC.
ANALOG TO DIGITAL CONVERTER-само ядро ADC.
DATA REGISTER-сюда будет записан результат преобразования аналогового сигнала в цифровой формат после конвертации если только не включена буферизация.
DATA BUFFER-буфер для хранения преобразований аналоговых сигналов, возможно использовать как буфер длиной по 10 или 8 десятибитных результатов преобразований, буферизация должна быть включена.
f MASTER-предделитель установки нужной частоты тактирования ADC которая зависит от напряжения на VDDA если оно будет в пределах от 2.95 до 5.5 вольт то должна быть не больше 4MHz или от 4.5 до 5.5 6MHz( влияет на точность преобразований).
ANALOG WATCHDOG-дополнительный модуль который выполняет функцию так называемой ждущей собаки или поподробней назначение сигнализировать( флаг прерывания) если результат преобразований выйдет за определенные рамки высокий и низкий предел который вы можете установить сами.
Описание функций SPL для работы с ADC.
ADC1_DeInit()-функция удаляет все настройки ADC1 и отключает его прерывания.
ADC1_Init( ADC1_ConversionMode, ADC1_Channel, ADC1_PrescalerSelection, ADC1_ExtTrigger, ADC1_ExtTriggerState, ADC1_Align, ADC1_SchmittTriggerChannel, ADC1_SchmittTriggerState)-основная функция настройки ADC, ниже описание параметров:
ADC1_ConversionMode-параметр определяет как будет работать модуль в одноразовом или продолжительном режиме.
ADC1_CONVERSIONMODE_SINGLE-преобразование делается только один раз.
ADC1_CONVERSIONMODE_CONTINUOUS-преобразования будут делаться постоянно пока не отключите.
ADC1_Channel-какой вывод подключен к ADC смотрите datasheet.
ADC1_CHANNEL_0-Analog input 0.
ADC1_CHANNEL_1-Analog input 1.
ADC1_CHANNEL_2-Analog input 2.
ADC1_CHANNEL_3-Analog input 3.
ADC1_CHANNEL_4-Analog input 4.
ADC1_CHANNEL_5-Analog input 5.
ADC1_CHANNEL_6-Analog input 6.
ADC1_CHANNEL_7-Analog input 7.
ADC1_CHANNEL_8-Analog input 8.
ADC1_CHANNEL_9-Analog input 9.
ADC1_CHANNEL_12-Analog input 12.
ADC1_PrescalerSelection-предделитель частоты тактирования ADC.
ADC1_PRESSEL_FCPU_D2-частота тактирования контроллера делённая на 2.
ADC1_PRESSEL_FCPU_D3- делённая на 3.
ADC1_PRESSEL_FCPU_D4- делённая на 4.
ADC1_PRESSEL_FCPU_D6- делённая на 6.
ADC1_PRESSEL_FCPU_D8- делённая на 8.
ADC1_PRESSEL_FCPU_D10- делённая на 10.
ADC1_PRESSEL_FCPU_D12- делённая на 12.
ADC1_PRESSEL_FCPU_D18- делённая на 18.
ADC1_ExtTrigger-выбор внешнего источника пуска преобразований.
ADC1_EXTTRIG_TIM-от таймера.
ADC1_EXTTRIG_GPIO-от вывода контроллера.
ADC1_ExtTriggerState-ENABLE-включаем пуск от внешнего источника, DISABLE-отключаем.
ADC1_Align-регистр где будет хранится результата преобразования является шестнадцатибитным а результат десятибитным поэтому его можно смешать в сторону старшего или младшего байта регистра.
ADC1_ALIGN_LEFT-биты от 9 до 2 будут смещены в старший байт, биты 1 и 0 останутся в младшем байте.
ADC1_ALIGN_RIGHT-биты 9 и 8 будут в старшем байте, биты от 7 до 0 в младшем байте.
ADC1_SchmittTriggerChannel-параметр выбирает вывод для включения или отключения SchmittTrigger, внутрисхемное отключения вывода от лишних узлов для предотвращения искажения конвертируемого сигнала.
ADC1_SCHMITTTRIG_CHANNEL0-Analog input 0.
ADC1_SCHMITTTRIG_CHANNEL1-Analog input 1.
ADC1_SCHMITTTRIG_CHANNEL2-Analog input 2.
ADC1_SCHMITTTRIG_CHANNEL3-Analog input 3.
ADC1_SCHMITTTRIG_CHANNEL4-Analog input 4.
ADC1_SCHMITTTRIG_CHANNEL5-Analog input 5.
ADC1_SCHMITTTRIG_CHANNEL6-Analog input 6.
ADC1_SCHMITTTRIG_CHANNEL7-Analog input 7.
ADC1_SCHMITTTRIG_CHANNEL8-Analog input 8.
ADC1_SCHMITTTRIG_CHANNEL9-Analog input 9.
ADC1_SCHMITTTRIG_CHANNEL12-Analog input 12.
ADC1_SchmittTriggerState-ENABLE не отключает от лишних компонентов SchmittTrigger, DISABLE используется для точного преобразования.
ADC1_Cmd( NewState)-NewState ENABLE включает ADC и преобразование, DISABLE отключает.
ADC1_StartConversion()-функция запускает преобразование.
ADC1_ScanModeCmd( NewState)-NewState ENABLE включает режим в котором ADC будет автоматически преобразовывать начиная с ADC1_CHANNEL_0 и заканчивая ADC1_CHANNEL_9 выводами, если включить буфер( DATA BUFFER) то результат каждого вывода будет сохранятся в личном регистре. DISABLE отключает данную функцию.
ADC1_DataBufferCmd( NewState)-NewState ENABLE включает использование DATA BUFFER, DISABLE отключает.
ADC1_PrescalerConfig( ADC1_Prescaler)-функция устанавливает предделитель для тактирования ADC, описание смотрите выше в ADC1_Init.
ADC1_SchmittTriggerConfig( ADC1_SchmittTriggerChannel, NewState)-функция настраивает SchmittTrigger, описание смотрите выше в ADC1_Init.
ADC1_ConversionConfig( ADC1_ConversionMode, ADC1_Channel, ADC1_Align)-функция настраивает режим преобразования, описание смотрите выше в ADC1_Init.
ADC1_ExternalTriggerConfig( ADC1_ExtTrigger, NewState)-NewState ENABLE функция подключает ADC к внешнему триггеру для старта преобразований, DISABLE отключает. ADC1_ExtTrigger может быть ADC1_EXTTRIG_TIM( от таймера) или ADC1_EXTTRIG_GPIO( специальный вывод контроллера).
ADC1_AWDChannelConfig( Channel, NewState)-NewState ENABLE функция подключает нужный вывод к ANALOG WATCHDOG, DISABLE отключает. Channel возможные варианты соответствующие выводу.
ADC1_CHANNEL_0-Analog input 0.
ADC1_CHANNEL_1-Analog input 1.
ADC1_CHANNEL_2-Analog input 2.
ADC1_CHANNEL_3-Analog input 3.
ADC1_CHANNEL_4-Analog input 4.
ADC1_CHANNEL_5-Analog input 5.
ADC1_CHANNEL_6-Analog input 6.
ADC1_CHANNEL_7-Analog input 7.
ADC1_CHANNEL_8-Analog input 8.
ADC1_CHANNEL_9-Analog input 9.
ADC1_CHANNEL_12-Analog input 12.
ADC1_SetHighThreshold( Threshold)-функция устанавливает верхний порог срабатывания ANALOG WATCHDOG, Threshold шестнадцатибитное число.
ADC1_SetLowThreshold( Threshold)-функция устанавливает нижний порог срабатывания ANALOG WATCHDOG, Threshold шестнадцатибитное число.
ADC1_GetConversionValue()-функция возвращает шестнадцатибитный результат конвертации.
ADC1_GetBufferValue( Buffer);функция возвращает шестнадцатибитный результат конвертации из буфера, принимает номер ячейки буфера из которой хотим прочесть результат преобразования, значения Buffer возможны от 0 до 7 или от 0 до 9 в зависимости от размера буфера.
ADC1_GetAWDChannelStatus( Channel)-функция принимает номер вывода, вернет результат FlagStatus проверки SET подключен или RESET не подключен к ANALOG WATCHDOG.
ADC1_ITConfig( ADC1_IT, NewState)-функция включает нужное прерывание NewState ENABLE и DISABLE отключает.
ADC1_IT-выбор прерывания виды и описание ниже.
ADC1_IT_AWDIE-прерывание от ANALOG WATCHDOG, уровень сигнала вышел за рамки.
ADC1_IT_EOCIE-прерывание от окончания преобразования.
ADC1_GetFlagStatus( Flag)-функция принимает проверяемое прерывание Flag, возвращает SET если прерывание сработало или RESET нет, описание Flag ниже.
ADC1_FLAG_OVR-флаг указывающий что буфер полон и будет переписан, сбрасывается программно.
ADC1_FLAG_AWD-флаг срабатывания прерывания от ANALOG WATCHDOG, если ADC используется в непрерывном или сканирование всех выводов то сработанный предел будет записан в буфер, сбрасывается программно.
ADC1_FLAG_EOC-флаг указывает что произошло прерывание от окончания преобразования аналогового сигнал в цифровой результат или если включен буфер после его заполнения, сбрасывается программно.
ADC1_ClearFlag( Flag)-функция принимает прерывание флаг которой надо очистить, описание Flag тоже самое что и у функции выше.
ADC1_GetITStatus( ITPendingBit)-функция проверяет PendingBit или тот же флаг прерывания но только для выводов когда включен ANALOG WATCHDOG, вернет SET если прерывание сработало или RESET если нет.
Варианты для ITPendingBit номера выводов:
ADC1_IT_AWS0
ADC1_IT_AWS1
ADC1_IT_AWS2
ADC1_IT_AWS3
ADC1_IT_AWS4
ADC1_IT_AWS5
ADC1_IT_AWS6
ADC1_IT_AWS7
ADC1_IT_AWS8
ADC1_IT_AWS9
Также флаги прерываний:
ADC1_IT_AWD
ADC1_IT_EOC
ADC1_ClearITPendingBit( ITPendingBit)-функция очищает ITPendingBit, варианты те же что и в функции выше.
Практика использования ADC и примеры программ.
Далее примерах я буду использовать контроллер STM8S903K3 и помогать будет LCD экран 1602а на который будем выводить нужную информацию как его подключить смотрите здесь уточню линия передачи данных по четырем проводам.
Ниже две схемы первая которую я буду использовать для примеров статьи и вторая как подключать схему стабилизации к выводам VDDA, VSSA.
Если хотите получать стабильную работу выбирайте контроллеры с выводами VDDA и VSSA а также используйте обязательно схему стабилизации, у контроллеров у которых нет данных выводов более подвержены помехам.
Первым делом как выбрать подходящий вывод контроллера для использования ADC, смотрим datasheet и выбираемым выводы с пометкой Analog input.
Теперь как все это работает все очень просто настраиваем порт как аналоговый вход, настраиваем ADC запускаем его для преобразования сигнала, ждем флага окончания преобразования и забираем из регистра результат вроде просто но теперь поподробней на практике.
Первый пример вольтметра который будет работать в режиме одиночного сканирования( single conversion) , сканируем и выводим результат ADC ниже вычисленное напряжение. На основе этого примера можно сделать простой вольтметр или амперметр.
#include "stm8s.h"
void pause( uint32_t p);
//инициализация дисплея вывод в первой строке ADC= и во второй VOLT=.
void displ_init( void);
//Функция отсылки команды по четырехбитной линии.
void send_comand_4bit( uint8_t data);
//Функция отсылки команды по восьмибитной линии.
void send_comand_8bit( uint8_t data);
//Функция отсылки данных по четырехбитной линии.
void send_data_4bit( uint8_t data);
//Функция отображения чисел.
void displ_number( uint32_t number);
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настраиваем порт для ADC вывод GPIOB pin3.
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
//Настраиваем сам ADC.
ADC1_Init( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D6, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
displ_init();
while(1){
//Очищаем флаг окончания преобразования.
ADC1_ClearFlag( ADC1_FLAG_EOC);
//Запускаем сканирование.
ADC1_StartConversion();
//Ожидаем окончания преобразования.
while( !ADC1_GetFlagStatus( ADC1_FLAG_EOC));
//Читаем результат преобразования.
uint32_t resultat=ADC1_GetConversionValue();
//Выводим информацию.
//Устанавливаем нужный адрес в дисплее и отображаем результат преобразования.
send_comand_4bit( 132);
displ_number( (uint16_t)(resultat));
//Опять меняем адрес в дисплее и выводим вычисленное напряжение.
send_comand_4bit( 197);
displ_number( resultat*5000/1024);
pause( 200000);
}
return 0;
}
//+++++Функции для экрана и assert_failed.+++++
void displ_init( void){
//Настройка выводов для D4-D7.
GPIO_Init( GPIOD, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_FAST);// DATA
GPIO_Init( GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);// DATA
GPIO_Init( GPIOD, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);// DATA
GPIO_Init( GPIOD, GPIO_PIN_7, GPIO_MODE_OUT_PP_LOW_FAST);// DATA
//Настройка выводов E, RS и R/W.
GPIO_Init( GPIOC, GPIO_PIN_7, GPIO_MODE_OUT_PP_LOW_FAST);// E Enable Signal
GPIO_Init( GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);// RS H--Data Input L--Instruction Input
GPIO_Init( GPIOC, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);// R/W H--Read L--Write
//Инициализация LCD три команды, одна перенастройка на 4 битную линию и 3 команды настройки.
pause( 10000);
send_comand_8bit( 48);
send_comand_8bit( 48);
send_comand_8bit( 48);
send_comand_8bit( 32);
send_comand_4bit( 40);
send_comand_4bit( 1);
send_comand_4bit( 14);
//Стандартно выводим наши символы.
send_data_4bit( 65);//A
send_data_4bit( 68);//D
send_data_4bit( 67);//C
send_data_4bit( 61);//=
send_comand_4bit( 192);
send_data_4bit( 86);//V
send_data_4bit( 79);//O
send_data_4bit( 76);//L
send_data_4bit( 84);//T
send_data_4bit( 61);//=
}
void displ_number( uint32_t number){
//send_data_4bit( number/10000+48);
//number= number-(number/10000*10000);
send_data_4bit( number/1000+48);
number= number-(number/1000*1000);
send_data_4bit( number/100+48);
number= number-(number/100*100);
send_data_4bit( number/10+48);
number= number-(number/10*10);
send_data_4bit( number+48);
}
void send_comand_8bit( uint8_t data){
GPIO_WriteLow(GPIOC, GPIO_PIN_5);
GPIO_WriteLow(GPIOC, GPIO_PIN_6);
pause( 5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_7);
//Стираем данные в D4-D7 для записи новых.
GPIOD->ODR &= 15;
//Записываем новые данные только в D4-D7.
GPIOD->ODR |= data&240;
pause( 5);
GPIO_WriteLow(GPIOC, GPIO_PIN_7);
pause( 2000);
}
void send_comand_4bit( uint8_t data){
GPIO_WriteLow(GPIOC, GPIO_PIN_5);
GPIO_WriteLow(GPIOC, GPIO_PIN_6);
pause( 5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_7);
GPIOD->ODR &= 15;
GPIOD->ODR |= data&240;
pause( 5);
GPIO_WriteLow(GPIOC, GPIO_PIN_7);
pause( 5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_7);
data=data<<4;
GPIOD->ODR &= 15;
GPIOD->ODR |= data&240;
pause( 5);
GPIO_WriteLow(GPIOC, GPIO_PIN_7);
pause( 2000);
}
void send_data_4bit( uint8_t data){
GPIO_WriteLow(GPIOC, GPIO_PIN_5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_6);
pause( 5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_7);
GPIOD->ODR &= 15;
GPIOD->ODR |= data&240;
pause( 5);
GPIO_WriteLow(GPIOC, GPIO_PIN_7);
pause( 5);
GPIO_WriteHigh(GPIOC, GPIO_PIN_7);
data=data<<4;
GPIOD->ODR &= 15;
GPIOD->ODR |= data&240;
pause( 5);
GPIO_WriteLow(GPIOC, GPIO_PIN_7);
pause( 2000);
}
void pause( uint32_t p){
for( uint32_t i=0; i<p; i++){ }
}
#ifdef USE_FULL_ASSERT
void assert_failed( uint8_t* file, uint32_t line)
{
while (1){}
}
#endif
Внимание! В следующих примерах для экономии места в статье я не буду отображать код программы после надписи
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
вы можете сами его скопировать из первого примера после надписи.
//+++++Функции для экрана и assert_failed.+++++
Следующий пример делает тоже самое только сканирование происходит непрерывно и забор результата преобразования ADC происходит в прерывании в теле программы мы просто выводим результат.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint32_t resultat;
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_Init( ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
ADC1_ClearFlag( ADC1_FLAG_EOC);
//Включаем прерывание от окончания преобразования.
ADC1_ITConfig( ADC1_IT_EOCIE, ENABLE);
enableInterrupts();
ADC1_StartConversion();
while(1){
send_comand_4bit( 132);
displ_number( (uint16_t)(resultat));
send_comand_4bit( 197);
displ_number( resultat*5000/1024);
}
return 0;
}
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
if( ADC1_GetFlagStatus( ADC1_FLAG_EOC)){
//Читаем результат преобразования.
resultat=ADC1_GetConversionValue();
ADC1_ClearFlag( ADC1_FLAG_EOC);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Следующий пример мы будем использовать буфер ADC и прерывание от его заполнения после которого мы сохраним в массив все десять преобразований. В основном теле программы из массива результатов преобразований вычислим средний результат и выведи на экран его а также вольтаж.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint32_t resultat;
uint16_t buf[10];
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_Init( ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
ADC1_DataBufferCmd( ENABLE);
ADC1_ClearFlag( ADC1_FLAG_EOC);
//Включаем прерывание от заполнения буфера.
ADC1_ITConfig( ADC1_IT_EOCIE, ENABLE);
enableInterrupts();
ADC1_StartConversion();
while(1){
//Обнуляем переменную и вычисляем в неё средний показатель из 10 преобразований.
resultat=0;
for( uint8_t i=0; i<10; i++){ resultat+= buf[ i];}
resultat/=10;
send_comand_4bit( 132);
displ_number( ( uint16_t)( resultat));
send_comand_4bit( 197);
displ_number( resultat*5000/1024);
}
return 0;
}
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
if( ADC1_GetFlagStatus( ADC1_FLAG_EOC)){
//Читаем результат преобразований записанных в буфер.
for( uint8_t i=0; i<10; i++){buf[ i]=ADC1_GetBufferValue( i);}
ADC1_ClearFlag( ADC1_FLAG_EOC);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Пример использования external trigger или старт преобразования от внешнего источника в роли которого будет использоваться TIM1, выглядит это следующим образом настраиваем ADC режиме одиночного сканирования после включаем его триггер и подключаем к выходному триггеру таймера, таймер настраивается как обычный счетчик с включенным выходным триггером настроенный срабатывать от переполнения что и будет запускать ADC.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint32_t resultat;
uint16_t buf[10];
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
enableInterrupts();
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
//Теперь включаем триггер от TIM1, изменяя Prescaler или TIM1_Period меняется частота сканирования.
ADC1_Init( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, ENABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
ADC1_ClearFlag( ADC1_FLAG_EOC);
ADC1_ITConfig( ADC1_IT_EOCIE, ENABLE);
//Настройка таймера и его выходного триггера.
TIM1_TimeBaseInit( 200, TIM1_COUNTERMODE_UP, 65535, 0);
TIM1_SelectOutputTrigger( TIM1_TRGOSOURCE_UPDATE);
TIM1_Cmd( ENABLE);
while(1){
send_comand_4bit( 132);
displ_number( (uint16_t)(resultat));
send_comand_4bit( 197);
displ_number( resultat*5000/1024);
}
return 0;
}
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
if( ADC1_GetFlagStatus( ADC1_FLAG_EOC)){
//Читаем результат преобразований.
resultat=ADC1_GetConversionValue( );
ADC1_ClearFlag( ADC1_FLAG_EOC);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
И ещё пример для режима scan mode контроллер автоматически сканирует( преобразует) каждый канал всегда начиная с ADC1_CHANNEL_0 и заканчивается ADC1_CHANNEL_4( максимальное ADC1_CHANNEL_9 десять каналов) то есть пять выводов и как вы наверное поняли ADC1_CHANNEL_4 теперь указывает контроллеру не номер канала а количество, после каждого выставления флага ADC1_FLAG_EOC этот параметр сбрасывается по этому устанавливайте его постоянно перед новым сканированием. Режим ADC1_CONVERSIONMODE_SINGLE не говорит что однократное сканирование и отключение ADC он указывает что флаг ADC1_FLAG_EOC выставится после сканирование указанного количества каналов, останавливается ADC1_Cmd( DISABLE).
Тут в ADC= отображается результат преобразований полученный с вывода GPIOB pin2 и VOLT= GPIOB pin3.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint16_t resultat1;
uint16_t resultat2;
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_2, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_Init( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_4, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
ADC1_SchmittTriggerConfig( ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);
ADC1_DataBufferCmd( ENABLE);
ADC1_ScanModeCmd( ENABLE);
ADC1_ClearFlag( ADC1_FLAG_EOC);
//Включаем прерывание от заполнения буфера.
ADC1_ITConfig( ADC1_IT_EOCIE, ENABLE);
enableInterrupts();
ADC1_StartConversion();
while(1){
send_comand_4bit( 132);
displ_number( resultat1);
send_comand_4bit( 197);
displ_number( resultat2);
pause( 10000);
}
return 0;
}
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
if( ADC1_GetFlagStatus( ADC1_FLAG_EOC)){
//Забираем первый результата.
resultat1=ADC1_GetBufferValue( 2);
//Забираем второй результат.
resultat2=ADC1_GetBufferValue( 3);
ADC1_ClearFlag( ADC1_FLAG_EOC);
//Устанавливаем новое количество каналов для начала сканирования.
ADC1_ConversionConfig( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_4, ADC1_ALIGN_RIGHT);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Тот же пример но без прерывания.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint16_t resultat1;
uint16_t resultat2;
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_2, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_Init( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_4, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
ADC1_SchmittTriggerConfig( ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);
ADC1_DataBufferCmd( ENABLE);
ADC1_ScanModeCmd( ENABLE);
ADC1_ClearFlag( ADC1_FLAG_EOC);
ADC1_StartConversion();
while(1){
ADC1_ConversionConfig( ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_4, ADC1_ALIGN_RIGHT);
while( !ADC1_GetFlagStatus( ADC1_FLAG_EOC));
ADC1_ClearFlag( ADC1_FLAG_EOC);
resultat1=ADC1_GetBufferValue( 2);
resultat2=ADC1_GetBufferValue( 3);
send_comand_4bit( 132);
displ_number( resultat1);
send_comand_4bit( 197);
displ_number( resultat2);
pause( 10000);
}
return 0;
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Пример с использованием ANALOG WATCHDOG, тут просто если результат преобразований будет выходит за установленные пределы в VOLT= он будет отображён. Когда включены одновременно два прерывания от ADC1_IT_EOCIE и ADC1_IT_AWDIE то при срабатывании последнего будет отключаться преобразования ADC поэтому его нужно заново включать.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint32_t resultat;
uint32_t resultat_volt;
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_DeInit();
ADC1_Init( ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
//Верхний предел срабатывания контроля напряжений.
ADC1_SetHighThreshold( 800);
//Низкий предел срабатывания контроля напряжений.
ADC1_SetLowThreshold( 400);
ADC1_ClearFlag( ADC1_FLAG_EOC);
ADC1_ClearFlag( ADC1_FLAG_AWD);
//Включаем прерывание от окончания преобразования.
ADC1_ITConfig( ADC1_IT_EOCIE, ENABLE);
//Включаем прерывание от выхода за рамки преобразований.
ADC1_ITConfig( ADC1_IT_AWDIE, ENABLE);
enableInterrupts();
ADC1_StartConversion();
while(1){
send_comand_4bit( 132);
displ_number( (uint16_t)(resultat));
send_comand_4bit( 197);
displ_number( (uint16_t)(resultat_volt));
}
return 0;
}
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
//Обработчик ANALOG WATCHDOG.
if( ADC1_GetFlagStatus( ADC1_FLAG_AWD)){
resultat_volt=ADC1_GetConversionValue();
ADC1_ClearFlag( ADC1_FLAG_AWD);
//Включаем снова преобразование.
ADC1_StartConversion();
}
//Обработчик окончания преобразования.
if( ADC1_GetFlagStatus( ADC1_FLAG_EOC)){
resultat=ADC1_GetConversionValue();
ADC1_ClearFlag( ADC1_FLAG_EOC);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Последний пример, тот же что и выше только прерывание будет срабатывать от ANALOG WATCHDOG.
#include "stm8s.h"
void pause( uint32_t p);
void displ_init( void);
void send_comand_4bit( uint8_t data);
void send_comand_8bit( uint8_t data);
void send_data_4bit( uint8_t data);
void displ_number( uint32_t number);
uint32_t resultat;
uint32_t resultat_volt;
int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
displ_init();
GPIO_Init( GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT);
ADC1_DeInit();
ADC1_Init( ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
//Верхний предел срабатывания контроля напряжений.
ADC1_SetHighThreshold( 800);
//Низкий предел срабатывания контроля напряжений.
ADC1_SetLowThreshold( 400);
ADC1_ClearFlag( ADC1_FLAG_AWD);
//Включаем прерывание от выхода за рамки преобразований.
ADC1_ITConfig( ADC1_IT_AWDIE, ENABLE);
enableInterrupts();
ADC1_StartConversion();
while(1){
resultat=ADC1_GetConversionValue();
send_comand_4bit( 132);
displ_number( (uint16_t)(resultat));
send_comand_4bit( 197);
displ_number( (uint16_t)(resultat_volt));
}
return 0;
}
//Обработчик ANALOG WATCHDOG.
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
if( ADC1_GetFlagStatus( ADC1_FLAG_AWD)){
resultat_volt=ADC1_GetConversionValue();
ADC1_ClearFlag( ADC1_FLAG_AWD);
}
}
//-----Ниже должны быть функции для экрана и assert_failed скопируйте из первого примера.-----
Дополнительная документация работы ADC stm8s_adc.pdf.