Перейти к содержанию

STM32F107RCT6 + ADS1256


Гость remixx

Рекомендуемые сообщения

Пытаюсь подключить ADS1256 (АЦП) к 107-мому по SPI .
Схему подключения, настройки МК и SPI, даташит АЦП - приложил.
Ну и собственно сам код:

Скрытый текст

/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT© 2018 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "math.h"
#include <string.h>
#include <errno.h>

#define CS_ON() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) // Vkluchenie ADC
#define CS_OFF() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) // Vikluchenie ADC
#define ADS_DRDY (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin)==GPIO_PIN_SET) // Proverka gotovnosti ADC
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi3;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t aTxBuffer[1]={0}; // Buffer dlya otpravlyaemih dannih
uint8_t aRxBuffer[3]={0,0,0}; // Buffer dlya prinimaemih dannih
uint32_t result;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* Funkciya inicializacii ADC */
void ADS1256_Init(void)
{
CS_ON(); // Aktiviruem ADC
HAL_Delay(100);
aTxBuffer[0]=0xFE; // Ukazivaem adres commandi RESET
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Posilaem komandy RESET (sbrasivaem ADC k defoltnim nastroykam)
HAL_Delay(100);

aTxBuffer[0]=0xFC;// Ukazivaem adres commandi SYNC
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Posilaem komandy SYNC (sinhronizaciya ADC s signalom na vivode SCLK)
aTxBuffer[0]=0x00; // Ukazivaem adres commandi WAKEUP
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Posilaem komandy WAKEUP (v sootvetstvii s datasheet)

aTxBuffer[0]=0x50 | 0x00; // Ukazivaem adress registra s kotorogo nachinaetsa zapis (STATUS)
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem adress pervogo registra
aTxBuffer[0]=3; // Ukazivaem kolichestvo registrov v kotorie budem zapisivat (zapisivaetsa 1 + TO KOLICHESTVO KOTOROE UKAZIVAEM, V DANOM SLUCHAE POLUCHAETSA 1+3=4)
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem kolichesto registrov

aTxBuffer[0]=0x04; // Ukazivaem dannie, kotorie neobhodimo zapisat v pervyi registr (STATUS) - ustanavlivaem poryadok chteniya so starshego bayta (MSB), vkluchaem avto-kalibrovky, vikluchaem analogovyi buffer, dubliruem vivod DRDY
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem dannie v registr STATUS
/* while(ADS_DRDY) {}; // Vozmojno nujno dlya ojidaniya zaversheniya avtokalibrovki */

aTxBuffer[0]=0x00 | 0x01; // Ukazivaem dannie, kotorie neobhodimo zapisat vo vtoroy registr (MUX) - vkluchaem vhod AIN0 kak POSITIVE, AIN1 kak NEGATIVE
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem dannie v registr MUX

aTxBuffer[0]=0x00; // Ukazivaem dannie, kotorie neobhodimo zapisat v tretyi registr (ADCON) - otkluchaem CLK0/CLK1, otkluchaem datchik opredeleniya istochnika toka, ustanavlivaem vnutrennyi usilitel v 64 raza
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem dannie v registr ADCON

aTxBuffer[0]=0x82; // Ukazivaem dannie, kotorie neobhodimo zapisat v chetvertyi registr (DRATE) - zadaem skorost raboti ADC (kolichestvo viborok v sekundu), v dannom sluchae 100 SPS
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Peredaem dannie v registr DRATE

HAL_Delay(100); //min=50*(1/fCLKIN)=50*(1/7.68MHZ)=6500ns;max=whatever

CS_OFF(); // Vikluchaem ADC
HAL_Delay(100);
}

/* Funkciya polucheniya rezultata ODNOGO preobrazovaniya */
uint32_t ADS1256ReadData(void)
{
uint32_t sum=0;

CS_ON(); // Aktiviruem ADC

aTxBuffer[0]=0x01; // Ukazivaem adres commandi READ DATA
HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Posilaem komandy READ DATA (chtenie rezultata ODNOGO preobrazovaniya)
HAL_SPI_Receive(&hspi3, (uint8_t*)aRxBuffer, 3, 50); // Schitivaem poluchennyi rezultat (3 bayta)

sum = aRxBuffer[0];
sum = sum << 8; // Poetomy, posle kajdogo poluchennogo bayta provodim smeshenie na 8
sum |= aRxBuffer[1];
sum = sum << 8;
sum |= aRxBuffer[2];

CS_OFF(); // Vikluchaem ADC
return sum; // Vozvrashaem znachenie poluchennogo rezultata
}
/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration----------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();

MX_SPI3_Init();
/* USER CODE BEGIN 2 */
HAL_Delay(100);
ADS1256_Init();
HAL_Delay(100);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
result = ADS1256ReadData();
while (ADS_DRDY) {}
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */

}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL2_ON;
RCC_OscInitStruct.PLL2.PLL2MUL = RCC_PLL2_MUL8;
RCC_OscInitStruct.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV5;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

/**Configure the Systick interrupt time
*/
__HAL_RCC_PLLI2S_ENABLE();

/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI3 init function */
static void MX_SPI3_Init(void)
{

/* SPI3 parameter configuration*/
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_MASTER;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 7;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);

/*Configure GPIO pin : DRDY_Pin */
GPIO_InitStruct.Pin = DRDY_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DRDY_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : CS_Pin */
GPIO_InitStruct.Pin = CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct);
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
* @}
*/

/**
* @}
*/

/************************ © COPYRIGHT STMicroelectronics *****END OF FILE****/

 

В итоге во входной буфер приходят только нулевые значения.
Если посылать команду RDATAC (т.е. выполнять не единичное преобразование, а сделать так, чтобы АЦП постоянно слал 24 бита один за другим), результат такой же.

Не понимаю в чем проблема, не правильная инициализация или схема?

SHEMA.JPG

FULLMCU.JPG

SHEMA.JPG

FULLMCU.JPG

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Помимо того, что указано на схеме, к питанию подключены SYNC/PDWN и RESET (в соответствии с дш).
А вот кварц отсутствует. Детали уже приобрел, во вторник протестирую вместе с ним.

А с кодом никаких проблем? Может быть какие-то грубые ошибки, которые сразу в глаза бросаются?

Ссылка на комментарий
Поделиться на другие сайты

Код вообще редкостная гадость, что характерно для любителей калокуба - абсолютное непонимание  как и  С, так и самой периферии.

И еще ни один адепт калокуба не смог верно инициализировать SPI и плодотворно работать с ним, хотя работа с модулем абсолютно прозрачна.

Ну и сразу -

 (uint8_t*)aTxBuffer

Имя массива и есть указатель на его первый элемент.

Изменено пользователем dosikus
Ссылка на комментарий
Поделиться на другие сайты

Ну и какая ж такая тайна в инициализации spi? У меня около 50 устройств работают около года на кубе, spi там используется для общения с flash и fram. На spi нареканий не было ни разу. А по поводу кода согласен, все в одном файле, куча дилеев. Может оно на данном этапе и проще, но я бы сразу отучивался от такой манеры написания...

Ссылка на комментарий
Поделиться на другие сайты

Я планирую запустить SPI по прерываниям, но на данном этапе пока разбираюсь с самим АЦП проще делать в таком виде.Проблема была действительно в кварце, сегодня наконец-то добрался до платы, напаял его и все заработало! :yahoo:
Но сейчас появился следующий вопрос: как от кода АЦП перейти к человеческим значениям))
Придумал следующее:
 

#define CS_ON()             HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) // Vkluchenie ADC
#define CS_OFF()             HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) // Vikluchenie ADC

//Провожу инициализацию АЦП
void ADS1256_Init(void)
{
    CS_ON(); // Aktiviruem ADC
    HAL_Delay(100);
    aTxBuffer[0]=0xFE; // Ukazivaem adres commandi RESET
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Posilaem komandy RESET (sbrasivaem ADC k defoltnim nastroykam)

    aTxBuffer[0]=0xFC; // Ukazivaem adres commandi SYNC
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Posilaem komandy SYNC (sinhronizaciya ADC s signalom na vivode SCLK)
    aTxBuffer[0]=0x00; // Ukazivaem adres commandi WAKEUP
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Posilaem komandy WAKEUP (v sootvetstvii s datasheet)

        aTxBuffer[0]=0x50 | 0x00; // Ukazivaem adress registra s kotorogo nachinaetsa zapis (STATUS)
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem adress pervogo registra
    aTxBuffer[0]=3; // Ukazivaem kolichestvo registrov v kotorie budem zapisivat (zapisivaetsa 1 + TO KOLICHESTVO KOTOROE UKAZIVAEM, V DANOM SLUCHAE POLUCHAETSA 1+3=4)
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem kolichesto registrov

    aTxBuffer[0]=0x05; // Ukazivaem dannie, kotorie neobhodimo zapisat v pervyi registr (STATUS) - ustanavlivaem poryadok chteniya so starshego bayta (MSB), vkluchaem avto-kalibrovky, vikluchaem analogovyi buffer, dubliruem vivod DRDY
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem dannie v registr STATUS

    aTxBuffer[0]=0x00 | 0x01; // Ukazivaem dannie, kotorie neobhodimo zapisat vo vtoroy registr (MUX) - vkluchaem vhod AIN0 kak POSITIVE, AIN1 kak NEGATIVE
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem dannie v registr MUX

    aTxBuffer[0]=0x00; // Ukazivaem dannie, kotorie neobhodimo zapisat v tretyi registr (ADCON) - otkluchaem CLK0/CLK1, otkluchaem datchik opredeleniya istochnika toka, ustanavlivaem vnutrennyi usilitel v 64 raza
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem dannie v registr ADCON

    aTxBuffer[0]=0xD0; // Ukazivaem dannie, kotorie neobhodimo zapisat v chetvertyi registr (DRATE) - zadaem skorost raboti ADC (kolichestvo viborok v sekundu), v dannom sluchae 7500 SPS
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem dannie v registr DRATE

    HAL_Delay(1);

    CS_OFF(); // Vikluchaem ADC
}

/* Funkciya polucheniya rezultata ODNOGO preobrazovaniya */
uint32_t ADS1256ReadData()
{
    uint8_t i=0;
    uint32_t sum=0;
    uint32_t r=0;

CS_ON(); // Aktiviruem ADC
    aTxBuffer[0]=ADS1256_CMD_RDATA; // Ukazivaem adres commandi READ DATA
    HAL_SPI_Transmit(&hspi3, (uint8_t*)aTxBuffer, 1, 50); // Posilaem komandy READ DATA (chtenie rezultata ODNOGO preobrazovaniya)

    for(i=0;i<3;i++) // Sozdaem cikl, t.k. ADC 24-bitnyi, to polnyi rezultat odnogo izmereniya budet predstavlen v vide 3 baytov (3 raza priydet po 8 bit)
        {
        sum = sum << 8; // Poetomy, posle kajdogo poluchennogo bayta provodim smeshenie na 8
        HAL_SPI_Receive(&hspi3, (uint8_t*)aRxBuffer, 1, 50); // Schitivaem poluchennyi rezultat (bayt)
        r = aRxBuffer[0]; // Priravnivaem peremennuy r k poluchennomy baytu ot ADC
        sum |= r; // Summiruem poluchennyi bayt s tem, chto uje imeetsa
        }

    /* OTRICATELNOE CHISLO PREDSTAVLENO V DOPOLNITELNOM CODE, 24yi BIT UKAZIVAET ZNAK, 23 OSTLANIH ETO CHISLO */
    uint32_t negative = (sum & (1 << 23)) != 0; // Proveryaem znak poluchennogo chisla (esli 24yi bit raven 1, to chislo otricatelnoe, a esli on raven 0, to chislo polojitelnoe
    uint32_t result;
    int MAXnegative = 0x800000; // Ukazivaem maximalno vozmojnoe OTRICATELNOE znachenie
    if (negative) // Esli chislo otricatelnoe, to vosstanavlivaem PRYAMOY KOD
    {
        if (sum != MAXnegative) // Esli ono ne maximalno otricatelnoe
        {
            sum = sum ^ 0x800000; // Iskluchaem 24yi bit
            result = sum - 1; // Vozvrashaem edinicy v mladshyi razryad
             result = result ^ 0xFFFFFF; // Vozvrashaem inversiy i 1cy v 24 bit
         }
         else // Esli ono maximalno otricatelnoe, to vivodim 0x800000, tak kak pryamoy kod etogo chisla vosstanovit nevozmojno
         {
             result = MAXnegative;
         }
    }
    else // Esli chislo polojitelnoe, to vivodim ego bez kakih libo preobrazovanyi
    {
        result = sum;
    }

    CS_OFF(); // Vikluchaem ADC
    return result; // Vozvrashaem znachenie poluchennogo rezultata
}

 

Результат преобразования вывожу в соответствии с картинкой 1 (Data format, страница 23 дш)

После чего пытаюсь преобразовать код АЦП к человеческому виду и вывести его на ЖКИ.
На странице 24 (рисунок 2), написана формула выходного кода АЦП (с учетом калибровки). Соответственно если выразить оттуда Vin = ((Output/(FSC*beta))+OFC/alfa)*(2*vref); то я и получу нужное мне значение.
Для этого после калибровки я считываю регистры FSC и OFC, затем подставляю только что измеренное значение АЦП и опорное напряжение (мерил осциллографом = 2,48 В).

/* Chtenie znacheniya ukazannogo registra */
uint8_t ADS1256RREG(uint8_t regaddr)
{
        CS_ON(); // Aktiviruem ADC

    aTxBuffer[0]=0x10 | (regaddr & 0xF); // Ukazivaem adres registra s kotorogo nachinaetsa chtenie
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem adress nachalnogo registra
    
aTxBuffer[0]=0; // Ukazivaem kolichestvo registrov iz kotorih budut schitivatsa dannie (zapisivaetsa 1 + TO KOLICHESTVO KOTOROE UKAZIVAEM, V DANOM SLUCHAE POLUCHAETSA 1+0=1)
    HAL_SPI_Transmit(&hspi3, aTxBuffer, 1, 50); // Peredaem kolichestvo registrov
    
       HAL_SPI_Receive(&hspi3, aRxBuffer, 1, 50); //Schitivaem dannie iz registra
    
       CS_OFF(); // Vikluchaem ADC

       return aRxBuffer[0]; // Vozvrashaem peremennoy znachenie vibrannogo registra
}

//Считываю значение регистров OFC
uint32_t ADS1256OFCCalibration()
{
        CS_ON(); // Aktiviruem ADC
    uint32_t number1=0;
    number1 = ADS1256RREG(0x07); //Считываю значение из регистра OFC2
    number1 = number1 << 8; // posle kajdogo poluchennogo bayta provodim smeshenie na 8
    number1 |= ADS1256RREG(0x06); //Считываю значение из регистра OFC1
    number1 = number1 << 8;
    number1 |= ADS1256RREG(0x05); //Считываю значение из регистра OFC0
      return number1;
}

//Считываю значение регистров FSC
uint32_t ADS1256FSCCalibration()
{
    CS_ON(); // Aktiviruem ADC
    uint32_t number2=0;
    number2 = ADS1256RREG(0x0A); //Считываю значение из регистра FSC2
    number2 = number2 << 8; // posle kajdogo poluchennogo bayta provodim smeshenie na 8
    number2 |= ADS1256RREG(0x09); //Считываю значение из регистра FSC1
    number2 = number2 << 8;
    number2 |= ADS1256RREG(0x08); //Считываю значение из регистра FSC0
      return number2;
}


Для вывода на жки преобразую переменные в строку и вывожу её.
 

//Funkciya vivoda stroki//
void PrintStr(char* str)
{
    uint8_t i = 0;
    while (str[i] != 0)
    {
        SendByte(str[i], 1);
        HAL_Delay(10);
        i++;
    }
}

//Преобразование переменной double
void PrintFlt(double test)
{
char output[50];
snprintf(output, 50, "%f", test);
PrintStr(output);
}


Ну и собственно main:

/

/Переменные
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t aTxBuffer[1]={0}; // Buffer dlya otpravlyaemih dannih
uint8_t aRxBuffer[3]={0,0,0}; // Buffer dlya prinimaemih dannih
uint32_t result1;
uint32_t OFC;
uint32_t FSC;
double beta=1.8639f;
double vref=2.48f;
uint32_t alfa=0x400000;
double OTVET;
/* USER CODE END PV */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI3_Init();

  /* USER CODE BEGIN 2 */
      HAL_Delay(100);
    InitializeLCD();
      HAL_Delay(100);
      ADS1256_Init();
      HAL_Delay(100);
      FSC=ADS1256FSCCalibration();
      OFC=ADS1256OFCCalibration();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      ClearLCDScreen();
      SetCursor(0,2);
      PrintStr("Result");
      SetCursor(1,3);
      result1=ADS1256ReadData();
      OTVET=((result1/(FSC*beta))+OFC/alfa)*(2*vref);
      PrintFlt(OTVET);
      HAL_Delay(1000);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

 

В итоге на ЖКИ вижу значения по типу 0.3xxxxx 0.5xxxxxx 0.1xxxxx , которые меняются хаотично.
PS: инициализация ЖКИ точно выполнена правильно, т.к. использую его уже давно.

1.jpg

2.jpg

Ссылка на комментарий
Поделиться на другие сайты

проблема у тебя в арифметике. И в первую очередь почитай где нибудь как избавится от таковой с плавающей точкой. Поубирай все свои даблы и замени на целые типы. Приведи все вычисления к одному основанию. Глядишь, чего нибудь и получится

При использовании дискретного источника данных (в данном случае АЦП) применение математики с плавающей точкой не требуется никогда

рецептов на эту тему уже милиард, только сиди и читай. Заодно почитай про мультисэмплинг. Поможет избавиться от скачущих цифр

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

@mail_robot Ну и как же обойтись без плавающей запятой, например, у меня диапозон ацп 0 - 1024, после калибровки рабочий диапозон шкалы 4 - 1022, шкала 20 - 120 °С. Ну вот как?

Ссылка на комментарий
Поделиться на другие сайты

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

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...

Вернулся к работе, но после всех корректировок так ничего и не изменилось)
Может быть я неправильно настраиваю CPOL и CPHA?
Приложил картинку передачи сигналов из ДШ.
По-моему в настройках SPI нужно устанавливать CPOL - 0, CPHA - 1Edge.
Еще кстати заметил, что в настройках выводов SCK и MOSI настраиваются как AF, а MISO как Input. А разве MISO не должен тоже задаваться как AF?

diagrmma.JPG

Ссылка на комментарий
Поделиться на другие сайты

9 часов назад, Гость remixx сказал:

По-моему в настройках SPI нужно устанавливать CPOL - 0, CPHA - 1Edge.

MISO - Input floating / Input pull-up.

CPOL - 0, CPHA - 1 да так правильно.

На HAL все очень сложно и запутанно, какие-то лишние сущности. Там настроек на 4 строчки.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • Тюльгин Ю.М. Радиоконструктор 2016-03 Датчик пересечения ИК-луча Другая сфера применения аналоговых усилителей на основе микросхемы 4069 - инфракрасный датчик или фотоприемник инфракрасного сигнала. На рисунке 7 показана схема успешно эксплуатируемого уже несколько лет датчика, реагирующего на пересечение либо отражение инфракрасного луча. Интересно то, что в схеме нет широко используемых в таких случаях готовых интегральных фотоприемников. Сигнал принимается обычным ИК-фотодиодом, а усиление производится усилительными каскадами, выполненными на основе инверторов микросхемы 4069. Наличие шести инверторов в одном корпусе микросхемы 4069 позволяет весь датчик, как его приемную, так и передающую части выполнить на одной микросхеме 4069. Рис. 7. Схема датчика пересечения ИК-луча на микросхеме 4069. И так, схема показана на рис. 7. Как обычно, ИК-датчик работающий на отражение или пересечение луча состоит из передатчика ИК-луча и его приемника. Передатчик ИК-луча состоит из ИК-светодиода HL1 (здесь светодиод, такой как в пультах ДУ аппаратуры), токового ключа на транзисторах VТ1 и VТ2 и генератора импульсов частотой около 8-10 kHz. Импульсы с выхода мультивибратора на элементах D1.5 и D1.6 поступают через токовый ключ на VT1 и VT2 на ИК-светодиод HL1. Резистор R11 ограничивает ток через светодиод. HL1 излучает ИК вспышки, следующие с частотой 8-10 kHz. Если существует видимость между HL1 и FH1, излученные вспышки воздействуют на фотодиод FH1 ив нем возникают импульсы тока. Благодаря резистору R1 они преобразуются в импульсы напряжения. Переменное напряжение через конденсатор С1 поступает на первый усилитель на элементе D1.1. Его в усилительный режим переводит резистор R2. Далее, через С2 усиленное переменное напряжение поступает на усилитель на D1.2. В цепи ООС D1.2 есть резистор R3, который смещает его вход в сторону напряжения логической единицы. В результате его выход смещен в сторону логического нуля. Поэтому, в отсутствие входного сигнала напряжение на С3 соответствует логическому нулю. Но при наличии входного сигнала за счет работы детектора на VD1 напряжение на С3 увеличивается до логической единицы. Выходные импульсы формирует триггер Шмитта на элементах D1.3 и D1.4. Фотодиод РН302 можно заменить любым ИК-фотодиодом. Налаживание датчика сводится к подбору сопротивления R3, чтобы при отсутствии сигнала на выходе D1.4 был ноль, а при наличии сигнала - единица. Везде вместо микросхемы 4069 можно попробовать микросхему К561ЛН2.
    • А программатора нет чтоб попробовать залить загрузчик?
    • Мда... Ардуино приехала нерабочая. К компу подключаю - звук подключения есть, а компом не определяется. Маркировка микросхемы загрузчика стёрта.... Ну китайцы... Теперь ждём новую Ардуино, а я пока начну делать пульт.
    • ИМХО, только с24, с25, с12 имеет смысл проверить/заменить.
    • Я сам найду, вы мне название напишите пожалуйста.
    • Добрый вечер..)) Нет в моем случае лучше найти готовый для моего Цифровой осциллограф Instrustar ISDS205A 2 канала х 20 МГц.. Что касается измерительной техники я пасс.. стараюсь купить уже готовое..))
×
×
  • Создать...