STM32F4Discovery+LabWindowsCVI. Урок 1. Часть 0. Введение

Для тех, кому лень изучать С++ и С#...

Многие начинающие или даже имеющие за плечами большой опыт программирования программисты микроконтроллеров сталкиваются с проблемой написания более менее рабочего оконного приложения для управления микроконтроллером с ПК и отображения телеметрии. В большинстве случаев для этого нужно изучать языки программирования высокого уровня, такие как С++ и C#. Процесс изучения этих языков может привести программиста, который всю жизнь программировал только на С в ступор, потому что они очень сильно отличаются от обычного С, а изучение этих языков займет у него очень много времени.
Именно для таких людей компания NationalInstruments выпустила программу LabWindowsCVI, в которой весь код пишется на простом С и человек, который программировал только на С очень легко в ней разберется…

В этом топике хочу представить вам цикл уроков по программированию LabWindowsCVI с использованием отладочной платы STM32F4Discovery…

В процессе работы мы напишем простое приложение :

С помощью этого приложения мы сможем:
    -Управлять состоянием светодиодов;
    -Управлять яркостью синего светодиода;
    -Получать значения угловых ускорений со встроенного акселерометра;
    -Изменять значения на выходе ЦАП и изменять его с помощью АЦП.

Видео, демонстрирующее работу приложения представлено ниже:


Спасибо за внимание!

STM32F030F4 инициализируем ADC

ADC на PA0

Инициализация:
void ADC_Config(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  ADC_DeInit(ADC1);
  
  ADC_StructInit(&ADC_InitStructure);
  
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
  ADC_Init(ADC1, &ADC_InitStructure); 
  
  ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
  ADC_GetCalibrationFactor(ADC1);
  ADC_Cmd(ADC1, ENABLE);     
  
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
  
  ADC_StartOfConversion(ADC1);
}


Использование:

ADC_Config();
while(1) {
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    ADCValue = ADC_GetConversionValue(ADC1);
}


Вместо ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; можно написать ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;, тогда перед каждой оцифровкой надо будет вызывать ADC_StartOfConversion(ADC1);

Заодно есть вопрос. Подключаю PA0 через делитель к +3.3V, гоняю по циклу ADC_GetConversionValue(). Оцифрованые значения имеют разбежку +/-10. Это нормально поведение АЦП или я что-то не так делаю?

Configuration Wizard в KEIL. Продолжение на примере настройки USART, ADC для STM32F4xx

Итак, продолжаем настраивать периферию с помощью Configuration Wizard. Возможно в будущем появятся еще экземпляры по разным устройствам, и в итоге объединим все в один мегапроект. Ну это так, помечталось мне.
Начнем:

Читать дальше

Аналоговые мультиплексоры, ADC

Однажды понадобилось 16-ть каналов АЦП, при 8-ми имеющихся у MSP430G2553 ...

И это могло бы стать проблемой, не будь аналоговых мультиплексоров (коммутаторов, ключей)
Для примера приведена структурная схема TS5A3157 от TI

Так как он является одноканальным, то имеет всего два мультиплексируемых входа (Vnc и Vno).
Вывод Vcom — общий и всегда соединен с одним из аналоговых входов.
Вывод Vi определяет в каком состоянии будет находится «переключатель».
Мультиплексоры пропускают ток в обоих направлениях и в идеале должны вести себя как выключатель, но реальность вносит своих коррективы.

Читать дальше

STM32F407VG, ADC+DMA+USART

Написал программу ADC+DMA+USART.Микроконтроллер STM32F407VG. Почему-то не работает. Не могу понять почему… Суть программы: При подаче напряжения на выход АЦП, DMA2 передает данные в память после чего DMA1 передает данные в USART3 который шлет все в PC

/*******************************************************************/
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_adc.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_dma.h"
#include "misc.h"
/*******************************************************************/
uint16_t adc_buffer[64];
void ADC_INIT(void)
{
//ADC Initialization
ADC_InitTypeDef  ADC_InitStructure;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_3Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

//ADC On to work with DMA
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
}




void USART_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStructure;

// USART TX
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
		GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

		GPIO_Init(GPIOB, &GPIO_InitStruct);	
	
//USART Initialization
		USART_InitStructure.USART_BaudRate = 115200;
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;
		USART_InitStructure.USART_StopBits = USART_StopBits_1;
		USART_InitStructure.USART_Parity = USART_Parity_No ;
		USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
		USART_InitStructure.USART_Mode = USART_Mode_Tx;
		USART_Init(USART3, &USART_InitStructure);
		USART_Cmd(USART3, ENABLE);
		USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
}

void DMA1_USART(void)
{
	DMA_InitTypeDef DMA_InitStructure;
  DMA_InitStructure.DMA_Channel = DMA_Channel_4;  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR);
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_buffer[0];
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = 64;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream1, &DMA_InitStructure);
  DMA_Cmd(DMA1_Stream1, ENABLE);
}

void DMA2_INIT(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC1->DR;	
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_buffer[0];	
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 64;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
 
DMA_Cmd(DMA2_Stream0, ENABLE);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);   
}

void DMA2_Stream0_IRQHandler(void)
{ 
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
  }
int main()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	
//GPIO Initialization For ADC1
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOE, &GPIO_InitStruct);
	
//Interrapt from DMA
	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
    while(1)
    {
 	__NOP();
    }

}

  • -10
  • 12 ноября 2013, 02:12
  • Foxek

Вольтметр/амперметр для лабораторного БП


В ходе размышлений над проектом лабораторного блока питания решил я немного поизучать возможности AVR в качестве измерителя напряжения и тока. Как известно, контроллеры серии ATMega имеют 10-разрядный АЦП, который можно использовать для измерения.

Вообще, точные измерения любых величин — дело далеко не простое. Начинается все с резисторов повышенной точности, за ними идут источники опорного напряжения, а там уже и до термокомпенсации недалеко… Ну и хорошо бы иметь заведомо точный измерительный прибор для калибровки нашего изделия.

Но на этом не заканчивается, в дело вступают проблемы программного характера: не всегда полученное количество отсчетов АЦП можно непосредственно вывести на экран, вступают в силу ошибки накопления, округления и прочие.

Насколько возможно, я пытался уйти от всех этих проблем и сохранить простоту схемного решения. Заодно в программировании поупражняться. Конечно, это только макет, но он определяет приоритеты в конструировании готового прибора.

Итак, что же мы имеем?


Читать дальше

STM32 ADC+DMA+ITC+Усреднение

Происходит плановая доработка железяки и разборки с АЦП в STM32, хочется использовать DMA и написать простой код. А также имеет место импульсное питание и собственно показания скачут, т.е. нужно все усреднять желательно по нескольким десяткам значений на каждое измерение.


Читать дальше

Измерение напряжения питания

AVR
В различных батарейных и аккумуляторных девайсах бывает не лишним отображать оставшийся заряд и/или иметь возможность вовремя отрубиться, чтобы не переразряжать аккумулятор. Для этого нужно измерять напряжение питания, что обычно делается с помощью встроенного ADC. Впрочем, ADC может отсутствовать (например, в тиньке 2313) или быть недоступен — заниматься более важным делом, либо в качестве опоры может использоваться то самое напряжение питания, etc.

В таком случае, напряжение питания несложно измерить с помощью встроенного аналогового компаратора, используя только одну ножку.

Схемка измерения напряжения


Читать дальше

Выбросы на ножках АЦП в STM32

РЕШЕНО- ПЕРЕЗАРЯД КОНДЕНСАТОРА АЦП
При работе с АЦП STM32F100,103 в 64 ногих корпусах обращал внимание на неадекватное поведение сигналов с АЦП — сильно скакали, при этом каких то адекватных объяснений найти не удавалось.


Читать дальше

Вольтметр на ICL7135 (+-20000 отсчетов)

(Melted_Metal написал вопрос в письме, но думаю, интересно будет и кому-нибудь еще.)



ICL7135 — АЦП двойного интегрирования.

Вкратце, принцип работы такой: подается clock примерно постоянной частоты (достаточно простейшего RC-генератора). Далее, т.н. секвенсор подключает измерительный вход через резистор к входу интегратора на некоторое точно отмеренное время (например, 20000 импульсов clock). Далее через тот же резистор подключается источник опорного напряжения, но в полярности, разряжающей конденсатор интегратора, при этом считаются импульсы до прохода напряжением конденсатора нуля. Количество импульсов и будет значением напряжения на входе.


Читать дальше