реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Использование 6и каналов АЦП в STM32F103VBT6, Последовательный опрос 6и каналов
AntiDriver
сообщение Jun 27 2015, 19:14
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 106
Регистрация: 1-05-13
Пользователь №: 76 699



Доброе время суток.
Являюсь новичком в программировании контроллеров STM на языке С. До этого довольно давно писал программы на ассемблере для 8-разрядных PIC.
Передо мной стоит следующая задача: имеется микроконтроллер STM32F103VBT6, 6 ножек которого (PA0..PA5) используются как входы AN0..AN5 для встроенного АЦП. Необходимо организовать последовательную оцифровку каждой ножки с передачей значения по USART.
На данном этапе я запустил только один канал АЦП и настроил передачу по USART. Так же получилось задействовать два канала АЦП. А вот с 6ю возникли проблемы. Настроил по USART передачу всех шести значений, в итоге вижу "C7 C7 9A 9A 00 00". Значение C7 соответствует значению, которое подается на AN0, а значение 9A соответствует AN1. Значение 00 не соответствует значению на ножке AN2. Просьба указать где именно в коде я оказался не прав.
Дополнительно, есть некоторые проблемы с GPIO. Ножка PB3 настроена на вход, однако с неё всегда считывается "0" не смотря на реальное значение напряжения, замеренное непосредственно на самой ножке вольтметром, а PB4, настроенная на выход, всегда выдает "1". JTAG не использую (использую SWD), отключил командой PIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE), но как понимаю, этого не достаточно.

Полный код в прикрепленном файле, код для инициализации и считывания с АЦП указан ниже:

CODE
#include "stm32f10x_rcc.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "misc.h"
#include "delay.h"

void SetupUSART(void);
void ADC1_2_IRQHandler(void);
void send_to_uart(uint8_t data);
void Get_Temp(void);

static volatile uint16_t temp[] = {0,0,0,0};
void ADC1_2_IRQHandler(void);
void send_to_uart(uint8_t data);
void Get_Temp(void);


int main(void)
{


SysTick_Config(72000);
RCC_APB2PeriphClockCmd(RCC_APB2ENR_AFIOEN, ENABLE); // ??
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;

// PORTA
// input
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);


// PORTB
// input
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// output
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

// PORTC
// input
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// output
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);

// PORTD
// input
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);

// PORTE
// input
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOE, &GPIO_InitStructure);
// output
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);

// ADC
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

ADC_DeInit(ADC1);

ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 6;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
NVIC_Init(&NVIC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1)) { };
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1)) { };


SetupUSART();

while(1)
{

GPIO_SetBits(GPIOC,GPIO_Pin_6);

Delay_ms(500);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);

Delay_ms(500);

Get_Temp();
unsigned char adc_value_0 = temp[1]>>4;
unsigned char adc_value_1 = temp[2]>>4;
unsigned char adc_value_2 = temp[3]>>4;
unsigned char adc_value_3 = temp[4]>>4;
unsigned char adc_value_4 = temp[5]>>4;
unsigned char adc_value_5 = temp[6]>>4;
send_to_uart(adc_value_0);
send_to_uart(adc_value_1);
send_to_uart(adc_value_2);
send_to_uart(adc_value_3);
send_to_uart(adc_value_4);
send_to_uart(adc_value_5);
}
}


void send_to_uart(uint8_t data)
{
while(!(USART1->SR & USART_SR_TC));
USART1->DR=data;
}

void ADC1_2_IRQHandler(void) {
if (ADC_GetITStatus(ADC1, ADC_IT_EOC)) {
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
temp[1] = ADC_GetConversionValue(ADC1);
temp[2] = ADC_GetConversionValue(ADC1);
temp[3] = ADC_GetConversionValue(ADC1);
temp[4] = ADC_GetConversionValue(ADC1);
temp[5] = ADC_GetConversionValue(ADC1);
temp[6] = ADC_GetConversionValue(ADC1);
}
}

void Get_Temp(void)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_1Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

}


Сообщение отредактировал IgorKossak - Jun 28 2015, 09:27
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
seniorandre
сообщение Jun 27 2015, 20:46
Сообщение #2


Участник
*

Группа: Свой
Сообщений: 58
Регистрация: 6-07-12
Из: г.Нижний Новгород
Пользователь №: 72 651



На вскидку..
1. Буфер tmp[] на 4 значения, а записывается 6 значений.
2. Continuous mode подразумевает что работа ADC продолжается, для каждого канала выполняется singleconversion. Но у Вас считываются значения во время очередной конверсии неизвестно какого канала, а по сути неизвестно чего. Надо либо читать каналы в single mode, остановить преобразование до считывания значения канала, а затем получать значение следующего канала, либо использовать DMA, чтобы значения сразу помещались в буфер (а правильнее чередовать два буфера). А значения читать по прерыванию DMA.
Go to the top of the page
 
+Quote Post
AntiDriver
сообщение Jun 27 2015, 22:06
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 106
Регистрация: 1-05-13
Пользователь №: 76 699



seniorandre,
1) Да, это так, в tmp[] на 4 значения записывается 6 значений. Но если поменять на 6, то практически ничего не изменится.
2) Я понимаю что написано, но не знаю как это преобразовать в код. Я писал его методом копирования примеров в интернете. Опять же, знаю что такое DMA, но это куча времени разбираться в этом (день - тоже куча). А времени нет. Договаривался как-то с программистом что я подготовлю железо, а он код, но так получилось что всё придется делать мне. Так что в качестве помощи было бы неплохо указать у меня в коде где именно ошибка (или чего нет) и на что заменить/вставить.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 28 2015, 05:17
Сообщение #4


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Да выкиньте вы нахрен эти библиотеки, изучите регистры по референс мануалу, запрограммируйте их одним махом, и никогда не пропУстите чего-нибудь нужного.

А если разбираться "времени нет", значит, и "вам туда дорога".
Схему тоже в интернете скопировали?
Go to the top of the page
 
+Quote Post
AntiDriver
сообщение Jun 28 2015, 07:40
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 106
Регистрация: 1-05-13
Пользователь №: 76 699



ViKo, ну если честно, в вашем посте нет ни слова полезной информации. Ну а с теми кто так выпендривается я уже знаком, чаще всего дальше слов у них дело не уходит. Схему делал сам, с этим у меня проблем пока не было, а вот с программированием пока не всё гладко.
Go to the top of the page
 
+Quote Post
Ruslan1
сообщение Jun 28 2015, 08:23
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025



Цитата(AntiDriver @ Jun 28 2015, 10:40) *
ViKo, ну если честно, в вашем посте нет ни слова полезной информации. Ну а с теми кто так выпендривается я уже знаком, чаще всего дальше слов у них дело не уходит. Схему делал сам, с этим у меня проблем пока не было, а вот с программированием пока не всё гладко.

Ну, если честно, то с вечера до утра уже могли и сделать. Вам уже раньше написали что делать:
Цитата(seniorandre @ Jun 27 2015, 23:46) *
Надо либо читать каналы в single mode, остановить преобразование до считывания значения канала, а затем получать значение следующего канала

Сейчас у Вас гонки двух процессов- аппаратного АЦП записи и программного чтения, и где-то их нужно или синхронизировать аппаратно (DMA) или притормаживать софтово один до завершения текущего шага другого (запустили одно АЦП-подождали завершения АЦП- прочитали результат)

Если Вы работали с ассемблером и с ПИКом, то как Вы там это делали? точно так же делайте и тут, логика не поменялась, никаких чудес.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 28 2015, 09:52
Сообщение #7


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AntiDriver @ Jun 28 2015, 10:40) *
ViKo, ну если честно, в вашем посте нет ни слова полезной информации. Ну а с теми кто так выпендривается я уже знаком, чаще всего дальше слов у них дело не уходит. Схему делал сам, с этим у меня проблем пока не было, а вот с программированием пока не всё гладко.

Я работал и с PIC АЦП, и с STM32, в разных режимах. Так, как и описал, по референс мануалу. Другого пути я не представляю.
Go to the top of the page
 
+Quote Post
Эдди
сообщение Jun 29 2015, 05:09
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250



Вот вам пример с использованием DMA. Памяти под буфер выделяю в 9 раз больше числа каналов, чтобы при запросе данных делать еще и медианную фильтрацию.
Go to the top of the page
 
+Quote Post
AntiDriver
сообщение Jul 2 2015, 14:17
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 106
Регистрация: 1-05-13
Пользователь №: 76 699



Спасибо, попробую разобраться.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th June 2025 - 19:00
Рейтинг@Mail.ru


Страница сгенерированна за 0.0162 секунд с 7
ELECTRONIX ©2004-2016