Вольт Ампер Ватт метр

Ihor
Offline
Зарегистрирован: 10.11.2017

   Появилась идея сделать трехфазный измеритель электроэнергии. За основу был взят проект https://habr.com/ru/post/384597/ . Но я использовал вместо Atmega 1280 Blue Pill с процессором STM32F103C8T6 .  Экран TFT 3.5' 320x480 с контролером ILI9488 . Тачскрин в данном проекте не использовал. Экран подключен на второй канал SPI . Частота 36 Мгц. Сигнал LED подключен к +3.3В. Измеряемое напряжение трех фаз 220 Вольт через делители 1-3 (680 кОм + 680 кОм + 1 Мом ) и 10 кОм подаются на входы PA0, PA2, PA4 относительно средней точки созданой делителем 4 из двух резисторов 200 Ом между корпусом и +3.3 В. (Сигнал снимается с резистора 10 кОм. Второй вывод резистора 10 кОм подключен к средней точке делителя 4. На входы PA1, PA3, PA5 будут подаваться напряжение с трансформаторов тока или датчиков Хола. Сейчас коэффициенты рассчитаны под датчик Хола 20 А. Устанавливаются в этих строках    urms[j] = sqrt(utemp[j])*0.19;    irms[j] = sqrt(itemp[j])/100; Про АЦП и таймеры читал статьи http://mypractic.ru/urok-26-acp-stm32-obshhie-svedeniya-rezhimy-ustanovka-konfiguracii-cherez-registry-cmsis.html 

В программе подключены оба АЦП. Два регулярных канала и четыре инжектированных. Время выборки 41.5 цикл выбрано исходя из того чтобы можно было входной делитель сделать высокоомным. Итого шесть каналов измеряется за 14.5 мкс. в цикле 200 мкс . После накопления 4096 измерений (0.8 сек) таймер останавливается проводится вычисление результатов и вывод на экран. После паузы 2 сек включается таймер и цикл повторяется. Вид экрана

 

 Сигнал подавал с генератора сделанного по мотивам генератора Dimaxa на AD9833 - 2 штуки синфазные и  Si5351 с сенсорным управлением. Если кого то заинтересует код могу выложить 

#include "SPI.h"
#include <Adafruit_GFX.h>
#include <ILI9488.h>
#include <libmaple/dac.h>

#define TFT_CS         PB12
#define TFT_DC         PB6
#define TFT_LED        PA9
#define TFT_RST        PB7

ILI9488 tft = ILI9488(TFT_CS, TFT_DC, TFT_RST);

int i,j;  
int res[6];
unsigned long t_prev;
unsigned long t_now;
byte flag=0;

//save current voltage data
double urms[3], utemp[3] ;
int umoment[3], umoment_old[3] ;

//save current current data
double irms[3], itemp[3];
int imoment[3] ,imoment_old[3];

//number of tick from 0 to 4095
int N = 0;

//zero-cross dfetection for frequency calc
long voltage_zerocross[3], voltage_zerocross_old[3], signalperiod[3];

//zero-cross detection for phase calc
long current_zerocross[3], phaseperiod[3];

float S[3], P[3], Q[3];
float frequency[3];
float phase[3];

void setup() {
  Serial.begin(9600);
  pinMode(PB12, OUTPUT);
  pinMode(PA9, OUTPUT);
  pinMode(PC13, OUTPUT);
  pinMode(PB7, OUTPUT);
  SPI.setModule(2);// выбор SPI2
  
  tft.begin();
  tft.setRotation(0);
  tft.setTextColor(ILI9488_WHITE);  tft.setTextSize(2);
  tft.fillScreen(ILI9488_BLACK);
  tft.println("Hello World!");
  
  // установки таймера 2 на период 200 мкс
  RCC_BASE->APB1ENR|= (1<<0);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4
  RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM2EN; // разрешение тактирования таймера
  TIMER2_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB
  TIMER2_BASE->PSC = 719; // 10 мкс
  TIMER2_BASE->ARR = 19;  // * 20
  TIMER2_BASE->DIER |= (1<<0);
  timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, my_int);
  TIMER2_BASE->CR1 |= (1<<0);

// ADC1, ADC2
// пины PA0-PA7 аналог
  GPIOA_BASE->CRL=0x00000000;
// разрешение тактирование АЦП
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2
// предделитель АЦП = 10 (/6)
  RCC_BASE->CFGR &= ~(1<<14);
  RCC_BASE->CFGR |=  (1<<15);

  ADC1_BASE->SMPR2 = 0b00000000000000100100100100100100; 
// 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924
  ADC2_BASE->SMPR2 = 0b00000000000000100100100100100100; 
// 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924
  ADC1_BASE->SQR1  = 0x00000000;//1канал 0b00000000000100000000000000000000;  2 каналов - 0x00100000
  ADC1_BASE->SQR3  = 0x00000000; 
//0канал 0b00000000000000000000000000100000;  последовательность канал 0-1 0x00000020
  ADC2_BASE->SQR1  = 0x00000000;//1канал
  ADC2_BASE->SQR3  = 0x00000001;//1канал
  
  ADC1_BASE->JSQR  =  0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800
  ADC2_BASE->JSQR  =  0b00000000001100101001000000000000; // 4 инжектир. канала 4,5  =0x000329000

// включить ADC1  011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART
//CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15)
  ADC1_BASE->CR2 = 0x00000000;
  ADC2_BASE->CR2 = 0x00000000;
  ADC1_BASE->CR2 |=  (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); 
  // | (1<<15) | (1<<14) | (1<<13) | (1<<12); 
  ADC2_BASE->CR2 |=  (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); 
  
  ADC1_BASE->CR1 |=  (1<<8) | (1<<10) | (1<<16);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16
  ADC2_BASE->CR1 |=  (1<<8) | (1<<10) ;
  
  ADC1_BASE->CR2 |=  (1<<0);// включение ADC1 
  ADC2_BASE->CR2 |=  (1<<0);// включение ADC2 
  delay(1);
//калибровка
  ADC1_BASE->CR2 |=  (1<<2);
  ADC2_BASE->CR2 |=  (1<<2);
  while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
  while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
  
  tft.fillScreen(ILI9488_BLACK);
  tft.println("Hello World!");
  tft.println(RCC_BASE->CFGR,HEX);
}

void loop(void) {
  if(flag){
//has new data 
tft.fillScreen(ILI9488_BLACK);  
tft.setCursor(0, 0); 
tft.setTextSize(2);
tft.setTextColor(ILI9488_WHITE);
tft.println("VOLT AMPER WATT METER");
tft.println();
for(j=0;j<3;j++)    
    {
  if(j == 0)tft.setTextColor(ILI9488_YELLOW);
  if(j == 1)tft.setTextColor(ILI9488_GREEN);
  if(j == 2)tft.setTextColor(ILI9488_ORANGE);        
    frequency[j] = 5000 / ((float)(signalperiod[j]));
    phase[j] = (2*3.1416) *  phaseperiod[j] / signalperiod[j];
    S[j] = urms[j] * irms[j];
    P[j] = S[j] * cos (phase[j]);
    Q[j] = S[j] * sin (phase[j]);
    flag = 0;
  tft.setTextSize(4);
    tft.print("  Pfaze  "); tft.println(j+1);
  tft.setTextSize(2);  
    tft.println();
  tft.setTextSize(3);  
    tft.print("U="); tft.print(urms[j]);
    tft.print(" I=");  tft.println(irms[j]);
    tft.print("F="); tft.print(frequency[j],1);
    tft.print(" cos="); tft.println(cos(phase[j]),2);
    tft.print("S="); tft.print(S[j],0);
    tft.print(" P="); tft.print(P[j],0);
    tft.print(" Q="); tft.println(Q[j],0);
//  tft.setTextSize(2);  
    tft.println();  
  }  
  delay(2000);
  TIMER2_BASE->CR1 |= (1<<0);
  } 
}

void my_int(){
  
  ADC1_BASE->CR2 |= ADC_CR2_SWSTART;
  while(!(ADC1_BASE->SR & ADC_SR_EOC)) ; 
  res[0] = ADC1_BASE->DR;
  res[1] = ADC2_BASE->DR;
  while(!(ADC1_BASE->SR & ADC_SR_JEOC)) ; 
  res[2] = ADC1_BASE->JDR1;
  res[3] = ADC1_BASE->JDR2; 
  res[4] = ADC2_BASE->JDR3;
  res[5] = ADC2_BASE->JDR4;
  ADC1_BASE->SR &= ~ADC_SR_JEOC; // сброс флага
  ADC1_BASE->CR2 &= ~ADC_CR2_SWSTART;
  
for(j=0;j<3;j++){
  umoment[j] = res[2*j] - 2020;
  utemp[j] = utemp[j] + pow((double)(umoment[j]),2)/4096;
//zero-crossdetect
  if ((umoment_old[j] <= 0) && (umoment[j] > 0)){
  voltage_zerocross[j] = N;
  signalperiod[j] = voltage_zerocross[j] - voltage_zerocross_old[j];
  if (signalperiod[j] < 0){
  signalperiod[j] = 4096 - signalperiod[j];  
  }//calc signal period in ticks
  voltage_zerocross_old[j] = voltage_zerocross[j];
  }
  umoment_old[j] = umoment[j];

  imoment[j] = res[1+2*j] - 2020;
  itemp[j] = itemp[j] + pow((double)(imoment[j]),2)/4096;
  if ((imoment_old[j] <= 0) && (imoment[j] > 0)){
  phaseperiod[j] = N - voltage_zerocross[j];
  if (phaseperiod[j] < 0){
  phaseperiod[j] = 4096 - phaseperiod[j];
  }//calc phase period in ticks
  }
  imoment_old[j] = imoment[j];     
  }
    N++;
  
   if (N == 4095){
   TIMER2_BASE->CR1 &= ~(1<<0);
   //calc final result
   for(j=0;j<3;j++){
   urms[j] = sqrt(utemp[j])*0.19;
   irms[j] = sqrt(itemp[j])/100;
   utemp[j] = 0;
   itemp[j] = 0;
   }
   N = 0; flag = 1;
  if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13);
  else GPIOC_BASE->ODR |= (1 << 13);
   }
  }

 

Ihor
Offline
Зарегистрирован: 10.11.2017

Поправил код. Планирую в дальнейшем добавить запись на SD и считать мощность. Входы процессора РА0-РА5 нужно защитить диодами.


#include "SPI.h"
#include <Adafruit_GFX.h>
#include <ILI9488.h>
#include <libmaple/dac.h>

#define TFT_CS         PB12
#define TFT_DC         PB6
#define TFT_LED        PA9
#define TFT_RST        PB7

ILI9488 tft = ILI9488(TFT_CS, TFT_DC, TFT_RST);
  
unsigned long t_prev, t_now;
byte flag=0, flag_0 =0, flag_stop =1, N_D=0, flag_st;

//save current voltage, current data
double urms[3], utemp[3],irms[3], itemp[3] ;
int umoment[3], umoment_old[3], imoment[3] ,imoment_old[3] ;

//N-number of tick from 0 to 4999
int N = 0, i,j, k;
int res[6];
//zero-cross detection for frequency and phase calc
long voltage_zerocross[3], voltage_zerocross_old[3], signalperiod[3];
long current_zerocross[3], phaseperiod[3];

float S[3], P[3], Q[3], frequency[3], phase[3];

void setup() {
  Serial.begin(9600);
  pinMode(PB12, OUTPUT);
  pinMode(PA9, OUTPUT);
  pinMode(PC13, OUTPUT);
  pinMode(PB7, OUTPUT);
  SPI.setModule(2);// выбор SPI2
  
  timer_set ();
  adc_set () ;

  tft.begin();
  tft.setRotation(0);
  tft.setTextColor(ILI9488_WHITE);  tft.setTextSize(2);
  tft.fillScreen(ILI9488_BLACK);
  tft.println("Hello World!");
}

void loop(void) {
  
if(flag_0 & flag_stop){
  flag_0 = 0; 
  ADC1_BASE->CR2 |= ADC_CR2_SWSTART;
  while(!(ADC1_BASE->SR & ADC_SR_EOC)) ; 
  res[0] = ADC1_BASE->DR;
  res[1] = ADC2_BASE->DR;
  while(!(ADC1_BASE->SR & ADC_SR_JEOC)) ; 
  res[2] = ADC1_BASE->JDR1;
  res[3] = ADC1_BASE->JDR2; 
  res[4] = ADC2_BASE->JDR3;
  res[5] = ADC2_BASE->JDR4;
  ADC1_BASE->SR &= ~ADC_SR_JEOC; // сброс флага
  ADC1_BASE->CR2 &= ~ADC_CR2_SWSTART;
  
for(j=0;j<3;j++){
  umoment[j] = res[2*j] - 2020;
  utemp[j] = utemp[j] + pow((double)(umoment[j]),2)/5000;
//zero-crossdetect
  if ((umoment_old[j] <= 0) && (umoment[j] > 0)){
  voltage_zerocross[j] = N;
  signalperiod[j] = voltage_zerocross[j] - voltage_zerocross_old[j];
  if (signalperiod[j] < 0){
  signalperiod[j] = 5000 - signalperiod[j];  
  }//calc signal period in ticks
  voltage_zerocross_old[j] = voltage_zerocross[j];
  }
  umoment_old[j] = umoment[j];

  imoment[j] = res[1+2*j] - 2020;
  itemp[j] = itemp[j] + pow((double)(imoment[j]),2)/5000;
  if ((imoment_old[j] <= 0) && (imoment[j] > 0)){
  phaseperiod[j] = N - voltage_zerocross[j];
  if (phaseperiod[j] < 0){
  phaseperiod[j] = 5000 - phaseperiod[j];
  }//calc phase period in ticks
  }
  imoment_old[j] = imoment[j];     
  }
    N++;  
   if (N == 4999){
   N_D++;
   //calc final result
   for(j=0;j<3;j++){
   urms[j] = sqrt(utemp[j])*0.19;
   irms[j] = sqrt(itemp[j])/100;
   utemp[j] = 0;
   itemp[j] = 0;
   }
   
   N = 0; flag = 1;
   }
  }
  
  if(flag & (N_D == 2)){ 
 flag_stop = 0;
 N_D = 0;
//has new data 
 tft.fillScreen(ILI9488_BLACK);  
 tft.setCursor(0, 0); 
 tft.setTextSize(2);
 tft.setTextColor(ILI9488_WHITE);
 tft.println("VOLT AMPER WATT METER");
 tft.println();
  for(j=0;j<3;j++) {
  if(j == 0)tft.setTextColor(ILI9488_YELLOW);
  if(j == 1)tft.setTextColor(ILI9488_GREEN);
  if(j == 2)tft.setTextColor(ILI9488_ORANGE);        
  frequency[j] = 5000 / ((float)(signalperiod[j]));
  phase[j] = (2*3.1416) *  phaseperiod[j] / signalperiod[j];
  S[j] = urms[j] * irms[j];
  P[j] = S[j] * cos (phase[j]);
  Q[j] = S[j] * sin (phase[j]);
  flag = 0;
    tft.setTextSize(4);
    tft.print("  Pfaze  "); tft.println(j+1);
    tft.setTextSize(2);  
    tft.println();
    tft.setTextSize(3);  
    tft.print("U="); tft.print(urms[j]);
    tft.print(" I=");  tft.println(irms[j]);
    tft.print("F="); tft.print(frequency[j],1);
    tft.print(" cos="); tft.println(cos(phase[j]),2);
    tft.print("S="); tft.print(S[j],0);
    tft.print(" P="); tft.print(P[j],0);
    tft.print(" Q="); tft.println(Q[j],0);  
    tft.println();  
  }  
  flag_st = 1;
  }
  if((flag_st == 1)&(k==0)) flag_stop = 1; 
}

  void my_int(){
    flag_0 = 1; k++; 
    if(k==4999) {
      (k = 0);
      if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13);
      else GPIOC_BASE->ODR |= (1 << 13);}
    }
    
  void timer_set (){
  // установки таймера 2 на период 200 мкс
  RCC_BASE->APB1ENR|= (1<<0);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4
  RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM2EN; // разрешение тактирования таймера
  TIMER2_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB
  TIMER2_BASE->PSC = 719; // 10 мкс
  TIMER2_BASE->ARR = 19;  // * 20
  TIMER2_BASE->DIER |= (1<<0);
  timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, my_int);
  TIMER2_BASE->CR1 |= (1<<0);    
  }
  
  void adc_set () {
// ADC1, ADC2
// пины PA0-PA7 аналог
  GPIOA_BASE->CRL=0x00000000;
// разрешение тактирование АЦП
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2
// предделитель АЦП = 10 (/6)
  RCC_BASE->CFGR &= ~(1<<14);
  RCC_BASE->CFGR |=  (1<<15);

  ADC1_BASE->SMPR2 = 0b00000000000000100100100100100100; 
// 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924
  ADC2_BASE->SMPR2 = 0b00000000000000100100100100100100; 
// 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924
  ADC1_BASE->SQR1  = 0x00000000;//1канал 0b00000000000100000000000000000000;  2 каналов - 0x00100000
  ADC1_BASE->SQR3  = 0x00000000; 
//0канал 0b00000000000000000000000000100000;  последовательность канал 0-1 0x00000020
  ADC2_BASE->SQR1  = 0x00000000;//1канал
  ADC2_BASE->SQR3  = 0x00000001;//1канал
  
  ADC1_BASE->JSQR  =  0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800
  ADC2_BASE->JSQR  =  0b00000000001100101001000000000000; // 4 инжектир. канала 4,5  =0x000329000

// включить ADC1  011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART
//CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15)
  ADC1_BASE->CR2 = 0x00000000;
  ADC2_BASE->CR2 = 0x00000000;
  ADC1_BASE->CR2 |=  (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); 
  // | (1<<15) | (1<<14) | (1<<13) | (1<<12); 
  ADC2_BASE->CR2 |=  (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); 
  
  ADC1_BASE->CR1 |=  (1<<8) | (1<<10) | (1<<16);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16
  ADC2_BASE->CR1 |=  (1<<8) | (1<<10) ;
  
  ADC1_BASE->CR2 |=  (1<<0);// включение ADC1 
  ADC2_BASE->CR2 |=  (1<<0);// включение ADC2 
  delay(1);
//калибровка
  ADC1_BASE->CR2 |=  (1<<2);
  ADC2_BASE->CR2 |=  (1<<2);
  while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
  while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки    
  }
Ihor
Offline
Зарегистрирован: 10.11.2017

   Продолжил изучать АЦП . Мне нужно два быстрых канала для оцифровки сигнала. В результате поиска в интернете попал на сайт https://www.gameinstance.com/post/79/STM32-Oscilloscope 

Использовал идею установить тактирование АЦП частотой 36 Мгц . При этом все чудненько работает. Разрешение конечно не 12 бит, но сигнал 500 кГц выглядит так. Тут работают два АЦП со сдвигом 7 тактов. Вывод на экран растянут.

Фото с пленкой на экране хорошим не получается. Код для Блюпил с экраном ILI9341 3.2" под спойлером. Данные с двух АЦП через 1 канал DMA1 запмсываются в буфер.  Код это просто заготовка. Учился управлять АЦП и DMA через регистры. Далее с этого можно делать двухканальный осциллограф .

#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <libmaple/dma.h>
#include <XPT2046_Touchscreen.h>
#include "SPI.h"

// Touchs creen
#define CS_PIN    PA4 
#define TIRQ_PIN  PB0
// For the Adafruit shiel , these are the default.
#define TFT_DC         PB1
#define TFT_CS         PB11
#define TFT_RST        PB10

//Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(CS_PIN,255);// TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling

bool dma1_ch1_Active =1;
int buf_size = 1024;
uint32_t data32[1024];
int i; volatile int k;

int devider =2;
int dualMode =1;//0-одновременно 1-сдвиг на 7 тактов
int continue_ =1;
int cycl = 1; //1-1.5 cycl  0- 7.5 cycl

void setup() {
  pinMode(PB11,OUTPUT);
  pinMode(PA4,OUTPUT);
  pinMode(PC13, OUTPUT);
    timer3_set ();
    adc_set();
    dma_init();
    dma1_ch1_Active = 1;
    DMA1_BASE->CCR1  |=  (1<<0);// 0-вкл.DMA1 //   dma_enable(DMA1, DMA_CH1);
     

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  
  tft.setTextSize(2);  
  tft.print("DMA_test2");

}

void loop() {
  if(dma1_ch1_Active ==0){
  for(i=0; i<buf_size;i++){
    
  int32_t d32_2 = ((data32[i]&0xFFFF0000)>>20);
  int d_2 =  d32_2 ;
  tft.drawPixel(10*i,d_2+20,ILI9341_YELLOW);

  int32_t d32_1 = (data32[i]&0xFFFF)>>4;
  int d_1 =  d32_1;
  tft.drawPixel(10*i+5,d_1+20,ILI9341_WHITE);
  
  tft.drawPixel(2*d_2+100,2*d_1+100,ILI9341_RED);
  
  }
  }
}

static void DMA1_CH1_Event() {
  dma1_ch1_Active = 0;
}

  void my_int(){ 
    k++; 
    if(k==2499) {
      (k = 0);
      if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13);
      else GPIOC_BASE->ODR |= (1 << 13);}
    }
  void adc_set (void) {
// ADC1, ADC2
// пины PA0-PA7 аналог
//  GPIOA_BASE->CRL=0x00000000;
// пины PA0-PA1 аналог
  GPIOA_BASE->CRL &= ~((1<<1) | (1<<0));
// разрешение тактирование АЦП
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1
  RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2
// предделитель АЦП = 10 (/6)
  if(devider == 2){RCC_BASE->CFGR &= ~(1<<14); RCC_BASE->CFGR &= ~(1<<15);}
  if(devider == 4){RCC_BASE->CFGR &= ~(1<<15); RCC_BASE->CFGR |=  (1<<14);}
  if(devider == 6){RCC_BASE->CFGR &= ~(1<<14); RCC_BASE->CFGR |=  (1<<15);}  
  if(devider == 8){RCC_BASE->CFGR |=  (1<<15); RCC_BASE->CFGR |=  (1<<14);}
  
  ADC1_BASE->SMPR2 = 0x00009249; // 0b00000000000000100100100100100100; 
//1.5cycl 0x00 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924
  ADC2_BASE->SMPR2 = 0x00009249; //0b00000000000000100100100100100100; 
//1.5cycl 0x00 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924
if(cycl ==1){ADC1_BASE->SMPR2 =0x0; ADC2_BASE->SMPR2 =0x0;}

  ADC1_BASE->SQR1  = 0x00000000;//1канал 0b00000000000100000000000000000000;  2 каналов - 0x00100000
  ADC1_BASE->SQR3  = 0x00000000; 
//0канал 0b00000000000000000000000000100000;  последовательность канал 0-1 0x00000020

  ADC2_BASE->SQR1  = 0x00000000;//1канал  РА0
  ADC2_BASE->SQR3  = 0x00000000;//1канал вход РА1
  
//  ADC1_BASE->JSQR  =  0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800
//  ADC2_BASE->JSQR  =  0b00000000001100101001000000000000; // 4 инжектир. канала 4,5  =0x000329000

// включить ADC1  011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART
//CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15) extse l=19-17
  ADC1_BASE->CR2 = 0x00000000;
  ADC2_BASE->CR2 = 0x00000000;
  ADC1_BASE->CR2 |=  (1<<20) | (1<<19) | (1<<8); 
  // | (1<<15) | (1<<14) | (1<<13) | (1<<12);  (1<<22) | | (1<<18) | (1<<17)
  ADC2_BASE->CR2 |=  (1<<20) | (1<<19) ; 
  
  ADC1_BASE->CR1 |=  (1<<5) | (1<<17) | (1<<18);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16-19
  ADC2_BASE->CR1 |=  (1<<5);
  if(dualMode ==1){ADC1_BASE->CR1 |=  (1<<16);}
  if(continue_ ==1){ADC1_BASE->CR2 |=  (1<<1); ADC2_BASE->CR2 |=  (1<<1);}
  
  ADC1_BASE->CR2 |=  (1<<0) ;// включение ADC1 
  ADC2_BASE->CR2 |=  (1<<0) ;// включение ADC2 
  delay(1);
//калибровка
  ADC1_BASE->CR2 |=  (1<<2);
  ADC2_BASE->CR2 |=  (1<<2);
  while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
  while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки    
  }
 void dma_init(void){
    RCC_BASE->AHBENR |=  (1<<0);  //   dma_init(DMA1);
    DMA1_BASE->CCR1  |=  (1<<13) | (1<<11) | (1<<9) | (1<<7) | (1<<1); //   dma_init(DMA1);
   // 1-прерыв по оконч. 5-циркулярная запись.   
   //  dma_setup_transfer(DMA1, DMA_CH1, &ADC1->regs->DR, DMA_SIZE_32BITS, data32, DMA_SIZE_32BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));
   //   TRNS_CMPLT прерыв. по заполнению буфера MINC_MODE - автоинкремент памяти
     DMA1_BASE->CPAR1 = (uint32_t) &ADC1->regs->DR; //адрес регистра ADC1
     DMA1_BASE->CMAR1 = (uint32_t) &data32; //адрес буфера

     DMA1_BASE->CNDTR1 |=  (1<<10); // dma_set_num_transfers(DMA1, DMA_CH1, BUFFER_SIZE);
   
     dma_attach_interrupt(DMA1, DMA_CH1, DMA1_CH1_Event);
}

void adc_dma_enable(const adc_dev * dev) {
  //
  bb_peri_set_bit(&dev->regs->CR2, ADC_CR2_DMA_BIT, 1);
}

  void timer3_set (){
  // установки таймера 3 на период 200 мкс
  RCC_BASE->APB1ENR|= (1<<1);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4
  RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM3EN; // разрешение тактирования таймера
  TIMER3_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB
  TIMER3_BASE->PSC =719; // 10 мкс
  TIMER3_BASE->ARR =19;  // * 20
  TIMER3_BASE->DIER |= (1<<0);
  TIMER3_BASE->CR2 &= ~(1<<4) | (1<<6); //разрешение TRGO
  TIMER3_BASE->CR2 |= (1<<5);
  timer_attach_interrupt(TIMER3, TIMER_UPDATE_INTERRUPT, my_int);
  TIMER3_BASE->CR1 |= (1<<0);   //start  TIMER3
  }    

 

Ihor
Offline
Зарегистрирован: 10.11.2017

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

Возился с часами на Блюпил. В результате написал код для установки часов и преобразования в формат - (год,месяц,день, час, минута , секунда) без сторонней библиотеки. Начало 1 января 2021 года.

#include <libmaple/iwdg.h>
#include <libmaple/dma.h>
#include<libmaple/nvic.h>
#include <RTClock.h>
RTClock rt (RTCSEL_LSE);

int month_[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
uint32 tt,  count, d_ ;
int year_now  = 2021;
int month_now =  5;
int day_now   = 17;
int hour_now  =  23;
int min_now   =  16;
int sec_now   =  0;
int i,j,j_max, d_month =0, d_year =0, d_now, m_now, y_now;

void setup() {
  pinMode(PC13, OUTPUT);
  Serial.begin(115200);
  tt = RTC_BASE->CNTH <<16 |  RTC_BASE->CNTL;
  if(tt==0) RTC_set ();
}

void loop() {
    if (rt.getTime()!=tt){  
  kalk_time(); 
  Serial.print(y_now); Serial.print("/"); Serial.print(m_now); Serial.print("/"); Serial.print(d_now+1);Serial.print("-");
  Serial.print(hour_now); Serial.print(":"); Serial.print(min_now); Serial.print(":"); Serial.println(sec_now); 
  }
}


void RTC_set ()
{
 if((year_now % 4) == 0) {month_[1] = 29;} 
 j_max = year_now - 2021;
 if(j_max > 0){
 for(j=0; j<j_max; j++) {if(j%4 == 3){d_year = d_year +366;} else{ d_year = d_year + 365;} }
 }
 for(i=0; i<(month_now-1);i++) { d_month = d_month + month_[i];}
 count = 1609459200+(d_year + d_month + day_now-1)*86400 + hour_now*3600 + min_now*60 + sec_now;

  RTC_BASE->CRL |= RTC_CRL_CNF;     //Разрешить Запись в регистры RTC
  RTC_BASE->CNTH = count>>16;       //записать новое значение счетного регистра
  RTC_BASE->CNTL = count;
  RTC_BASE->CRL &= ~RTC_CRL_CNF;    //Запретить запись в регистры RTC 
  //if (rt.getTime()==0) { rt.setTime(count);} //записать новое значение счетного регистра если 0
}
void kalk_time(void){
  tt = RTC_BASE->CNTH <<16 |  RTC_BASE->CNTL; //  чтение счетного регистра 

  d_ = (tt - 1609459200)/86400;
  d_now = d_;
  d_ = (tt - 1609459200)%86400;
  sec_now   = d_ % 60;
  hour_now  = d_ / 3600;
  d_ = d_ % 3600;
  min_now   = d_ / 60; 
  i = 0; j = 0;
  while(d_now > (month_[i]-1)) {if(j%4 ==3){month_[1] = 29;}else {month_[1] = 28;}
  d_now = d_now - month_[i]; i++; if(i == 12){i=0; j++;}
  }
  m_now = i+1;
  y_now = j+2021;
 //rt.getTime(); //чтение счетного регистра
 // Serial3.print("time is: "); Serial3.println(tt);
}