Переглянути джерело

Закончил с обработкой результатов от АЦП.

Vladimir N. Shilov 9 роки тому
батько
коміт
d78b6a1365
11 змінених файлів з 359 додано та 226 видалено
  1. 4 1
      .gitignore
  2. 3 3
      Makefile
  3. 57 31
      ReadMe.txt
  4. 117 15
      lib/adc.c
  5. 10 16
      lib/adc.h
  6. 5 5
      lib/max7219.c
  7. 19 19
      lib/max7219.h
  8. 1 1
      lib/rtos.c
  9. 1 1
      lib/rtos.h
  10. 140 115
      src/main.c
  11. 2 19
      src/stm8l15x_it.c

+ 4 - 1
.gitignore

@@ -2,5 +2,8 @@ Out
 ~*.*~
 *.layout
 *.save
-Debug
 Result.log
+EWSTM8/Debug
+EWSTM8/Release
+EWSTM8/settings
+*.dep

+ 3 - 3
Makefile

@@ -42,7 +42,7 @@ LIST_DIR = $(OUT_DIR)/List
 
 # Models
 CODE_MODEL = small
-DATA_MODEL = small
+DATA_MODEL = medium
 
 # Application object files
 APP_OBJECTS = $(notdir $(patsubst %.c,%.o,$(wildcard $(APP_SRC)/*.c)))
@@ -119,7 +119,7 @@ LINKFLAGS = --redirect _Printf=_PrintfTinyNoMb
 LINKFLAGS += --redirect _Scanf=_ScanfSmallNoMb
 LINKFLAGS += --config "$(EWSTM8_DIR)\config\$(ICF)"
 LINKFLAGS += --config_def _CSTACK_SIZE=0x100
-LINKFLAGS += --config_def _HEAP_SIZE=0x100
+LINKFLAGS += --config_def _HEAP_SIZE=0x000
 LINKFLAGS += --map $(OUT_DIR)
 LINKFLAGS += --entry __iar_program_start
 LINKFLAGS += --merge_duplicate_sections
@@ -128,7 +128,7 @@ LINKFLAGS += -f "$(EWSTM8_DIR)\config\math_small.xcl"
 
 DBG_LINKFLAGS = --redirect _Printf=_PrintfTinyNoMb --redirect _Scanf=_ScanfSmallNoMb
 DBG_LINKFLAGS += --config "$(EWSTM8_DIR)\config\$(ICF)" --config_def
-DBG_LINKFLAGS += _CSTACK_SIZE=0x100 --config_def _HEAP_SIZE=0x100
+DBG_LINKFLAGS += _CSTACK_SIZE=0x100 --config_def _HEAP_SIZE=0x000
 DBG_LINKFLAGS += --entry __iar_program_start
 
 

+ 57 - 31
ReadMe.txt

@@ -2,10 +2,10 @@
 * Измеритель напряжения/тока/мощности/ёмкости *
 
 Немогу никак определиться с диапазонами.
-Думал сначал сделать по два диапозона на напряжение и ток, но что-то мне эта 
-идея разонравилась. Опять же, измерять большие напряжения/токи не особо часто 
+Думал сначал сделать по два диапозона на напряжение и ток, но что-то мне эта
+идея разонравилась. Опять же, измерять большие напряжения/токи не особо часто
 приходится. Напряжения в основном до 20 вольт, токи - до пары ампер.
-Тем более, так как это измеритель в конкретное устройство, то нужно под него и 
+Тем более, так как это измеритель в конкретное устройство, то нужно под него и
 подстраиваться.
 Будет по одному диапазону на ток и напряжения.
 
@@ -13,11 +13,11 @@
 сделать ввод Кд делителя напряжения умноженного на 1000,
 и сопротивление шунта * Ку услителя тока * 1000.
 
-Далее в программе при вычислениях - получили код ацп, перевели в напряжение, 
+Далее в программе при вычислениях - получили код ацп, перевели в напряжение,
 умножили на 1000 и поделили на коэффициент.
 
 Ох и здоровая (85х40мм) плата получилась...
-можно попробовать разбить на две -- на одной индикатор и кнопки, на второй всё 
+можно попробовать разбить на две -- на одной индикатор и кнопки, на второй всё
 остальное. получится две платы ~ 45х40 мм.
 
 вариант A -- поменял входной разъём.
@@ -31,9 +31,9 @@
 
 SVN-инит 2014.12.29
 
-появилась мысль -- сделать транзисторный ОК выход, например для управления 
+появилась мысль -- сделать транзисторный ОК выход, например для управления
 релюхой. хотя если брать ардуиновское реле -- то там нужен просто выход.
-реле для управления нагрузкой -- можно сделать тот-же зарядно-разрядный 
+реле для управления нагрузкой -- можно сделать тот-же зарядно-разрядный
 автомат.
 ===
 2014.12.30
@@ -82,24 +82,24 @@ SVN-инит 2014.12.29
 ---
 2016.03.24
 
-Так-как по прежнему тишь и глухомань, поднял проект в IAR-е и полез в 
+Так-как по прежнему тишь и глухомань, поднял проект в IAR-е и полез в
 отладку. Всё застряло где-то в Delay - похоже на проблемы с таймером.
-Таки да, забыл включить тактирование таймера -- похоже потерялось при 
+Таки да, забыл включить тактирование таймера -- похоже потерялось при
 переносе инициализации то туда, то сюда...
 
 Повторяем заповедь -- "Часы, ноги, перефирия".
 
-Вобщем, SPI работает. Проблема была в том, что токозадающий резистор для 
+Вобщем, SPI работает. Проблема была в том, что токозадающий резистор для
 MAX нужно подключать на +5В, а у меня он был на земле. Напаял навесом.
 Картинка появилась, но на индикаторах какой-то бред.
 
 Исправил коды символов. Исправил позиции индикаторов.
-Вылезло два момента -- неправильно запаял индикаторы, собирался красный 
-вниз, под ток, а жёлтый вверх под напряжение. В итоге запаял наоборот. Так 
-ещё и на схеме они местами попутаны, так как на плате DS1 внизу, а DS2 
+Вылезло два момента -- неправильно запаял индикаторы, собирался красный
+вниз, под ток, а жёлтый вверх под напряжение. В итоге запаял наоборот. Так
+ещё и на схеме они местами попутаны, так как на плате DS1 внизу, а DS2
 вверху. Исправил схему и позиции индикаторов под факт.
 
-Добился картинки. Похоже тут какой-то бешенный оптимизатор -- выкинул нах 
+Добился картинки. Похоже тут какой-то бешенный оптимизатор -- выкинул нах
 похожую функцию. Нужно учесть на будущее.
 
 ---
@@ -122,30 +122,30 @@ C_adc = 16 * 10^-12, т.е.:
 Factory_VREFINT у меня == 0x7E, т.е. полное значение 0x067E == 1662
 Если это мерялось при 3В, то получается -- 1.218 В
 
-Предварительный успех -- читаю три канала АЦП и ПДП складывает их в 
-память, преобразовываю и вывожу на индикаторы. Запуск АЦП каждые 10 мсек 
+Предварительный успех -- читаю три канала АЦП и ПДП складывает их в
+память, преобразовываю и вывожу на индикаторы. Запуск АЦП каждые 10 мсек
 тригером от Т2. Настройка Т2 пока заклинанием -- понимания нету.
-На очереди -- усреднение результатов, вычисление напряжения питания через 
+На очереди -- усреднение результатов, вычисление напряжения питания через
 опорное напряжение.
 
 Пока не сильно нравится -- завышает напругу, скачут показания.
 Мерял аккум - 4.219 В, мой точный показывал 4.207, DT-шка - 4.17-4.18 В.
 Канал внутреннего опорного напряжения показывает 1.219 - 1.223 В
-По каналу тока висит 4 мВ, мой 5-ти разрядный вольтметр показывал 3 мВ на 
+По каналу тока висит 4 мВ, мой 5-ти разрядный вольтметр показывал 3 мВ на
 выводе.
-По каналу напряжения постоянно висит 17-26-35 мВ, вольтметр показывет 
+По каналу напряжения постоянно висит 17-26-35 мВ, вольтметр показывет
 чёткий "0". Замыкание на землю ничего не даёт. Хз, что это такое.
-Если от итогового напряжения вычесть эти миливольты, то результат будет 
+Если от итогового напряжения вычесть эти миливольты, то результат будет
 больше похож на правду.
 
 На тему усреднения, такая идея:
  - в прерывании ПДП данные перекладываются в быстрый кольцевой буфер
    на 10 значений. Можно мерять чаще, хоть каждую 1 мс.
- - в основном теле каждые 100 мсек отрабатывает процедура, которая 
+ - в основном теле каждые 100 мсек отрабатывает процедура, которая
    усредняет данные из быстрого буфера, отбрасывая слишком мелкие/большие,
-   и перекладывает в медленный кольцевой буфер. Тут же делать пересчёты 
+   и перекладывает в медленный кольцевой буфер. Тут же делать пересчёты
    значений из кода АЦП в реальные значения.
- - ещё одна процедура раз в секунду усредняет данные из медленного буфера 
+ - ещё одна процедура раз в секунду усредняет данные из медленного буфера
    и сохраняем в текущий секундный результат. Здесь же вычеслять мощности,
    ёмкости, время и т.д.
 
@@ -154,11 +154,11 @@ Factory_VREFINT у меня == 0x7E, т.е. полное значение 0x067E
 
 Причесал настройку Т2.
 
-Считаем среднее, зануляем младшие 4 бита, и потом сравниваем каждое 
+Считаем среднее, зануляем младшие 4 бита, и потом сравниваем каждое
 значение со сброшенными 4-мя младшими битами:
   middle &= 0xFFF0;
   if ((value & 0xFFF0) == middle) { ... }
-таким образом отберём только те значения, которые отличаются от 
+таким образом отберём только те значения, которые отличаются от
 предварительного среднего не более чем на 1/16
 
 ---
@@ -166,8 +166,8 @@ Factory_VREFINT у меня == 0x7E, т.е. полное значение 0x067E
 
 Период измерений 1.25 мсек, быстрый буфер - на 16 значений.
 Фильтра нет, только усреднение.
-Понял, почему скачет опора -- при включеном светодиоде проседает 
-напряжение питания и завышаются показания. Что за хрень в канале напруги 
+Понял, почему скачет опора -- при включеном светодиоде проседает
+напряжение питания и завышаются показания. Что за хрень в канале напруги
 всё равно не понятно.
 Нужно срочно увеличивать резисторы в цепи светодиодов.
 Без светодиодов канал внутренней опоры показывает 1.219 В.
@@ -177,25 +177,25 @@ Factory_VREFINT у меня == 0x7E, т.е. полное значение 0x067E
 
 Начитался AN3137. Краткие выводы:
  - конденсаторы по входу АЦП нужно поменять на 220 нФ,
- - период измерения сделать не менее 2 мсек по упрощ'нной формуле,
+ - период измерения сделать не менее 2 мсек по упрощённой формуле,
    или не менее 1,2 мсек по полной формуле,
  - всё остальное -- отталкиваясь от этих данных.
 
 Подробнее:
 
- 1. внешний конденсатор (правда в некоторых слачаях его не нужно ставить, 
+ 1. внешний конденсатор (правда в некоторых слачаях его не нужно ставить,
 только я не понял в каких) расчитывается по так:
 	Cext ~= 1.58 * Csh * (Umax / Ulsb),
  где Csh -- внутрення ёмкость АЦП, 16 пФ,
  Umax -- максимальное входное напряжение, принимается 4096,
  Ulsb -- нужная точность, принимается 0.5 LSB.
 Итого, Cext ~= 1.58 * 0.000000000016 * (4096 / 0.5) >= 207 nF.
-Этот конденсатор должен держать входное напряжение, пока оно меряеться АЦП, 
+Этот конденсатор должен держать входное напряжение, пока оно меряеться АЦП,
 при этом он должен разрядиться не больше чем на Ulsb.
 Интересно, а можно его использовать для оверсемплинга, расчитав на 1 LSB ?
 Конденсатор на 10 нФ успевает разрдится на 6-10 LSB.
 
- 2. Период времени между измерениями, за который должен успеть зарядиться 
+ 2. Период времени между измерениями, за который должен успеть зарядиться
 входной конденсатор, расчитывается так:
 	tc = - (Rin * Csh) * ln(1 - (Csh/Cext) * (Umax/Ulsb))
 или, упрощённая формула tc ~= (Rin * Csh)
@@ -203,3 +203,29 @@ Factory_VREFINT у меня == 0x7E, т.е. полное значение 0x067E
  ln(1 - (Csh/Cext) * (Umax/Ulsb)) ~= 0.9058
 и в итоге, для канала вольтметра (как более высокоомного и медленного):
 	tc = (Rin * Csh) * 0.9058 = 9090 * 0.000000000016 * 0.9058 ~= 1,2 мсек
+
+---
+2016.07.27
+
+Попытка "ADC2" провалилась -- там что-то не то в буфере от АЦП.
+Возвращаюсь на последнюю рабочую версию и пойду другим путём.
+
+План:
+ - меряем два канала (напряжение и ток) каждые 1,5625 мсек;
+ - DMA забирает данные, в прерывании перебрасываем два слова в первичный
+   циклический буфер на 64 значения (два буфера под напряжение и ток?)
+   в этом буфере сырые данные (код от ацп);
+ - раз в 100 мсек усредняем/обрабатываем эти 64 значения и складываем во
+   второй буфер на 10 значений;
+ - раз в секунду усредняем и считаем данные из воторого буфера.
+
+ Закончил.
+ Получился слегка затянутым -- "фронт" изменения показаний около 3-х секунд.
+ Шаг вольтметра в 1 мВ я получил, но смысла особого не вижу :-)
+ Без "оверсэмплинга" показания более сабильны.
+
+ Фильтрация по каналу тока -- её не заметно. хз куда смотреть.
+ В канале тока постоянно "висит" 3-4 мА, когда-то я считал,
+ это похоже на смещение "0" от ОУ. Хз, нужно ли вычитывать их из результата.
+
+ Этот этап можно считать законченым.

+ 117 - 15
lib/adc.c

@@ -6,6 +6,11 @@
   * @date    24-March-2016
   * @brief   This file contains the ADC functions.
   ******************************************************************************
+  * Tim2 регулярно запускат АЦП.
+  * АЦП измеряет два заданных канала и пинает DMA
+  * DMA забирает данные у ADC и складывает их в ADC_Buffer
+  * В прерывании по окончанию транзакции данные из ADC_Buffer
+  * раскладываем по FastBuffers.
   */
 
 /* Includes ------------------------------------------------------------------*/
@@ -17,21 +22,34 @@
 
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
+#define VOLTAGE_CHANNEL     ADC_Channel_17
+#define CURRENT_CHANNEL     ADC_Channel_18
+#define ADC1_DR_ADDRESS     ((uint16_t)0x5344)
+#define ADC_BUFFER_ADDRESS  ((uint16_t)(&ADC_Buffer))
+
+#define ADC_REF             3300
+#define ADC_DIV             4095
+#define ADC_ODIV            32768
+#define ADC_VOLT_K          11
+#define ADC_CURR_K          20
+
+// (Частота МК (16 МHz) / Предделитель таймера (8) * Нужное время в секундах (0.0015625)) - 1
+#define TIM_PERIOD          ((uint16_t)3128)
+#define TIM_PRESCALER       TIM2_Prescaler_8
+
 /* Private macro -------------------------------------------------------------*/
 /* Private variables ---------------------------------------------------------*/
-uint16_t ADC_Buffer[ADC_BUFFER_SIZE] = {0, 0, 0};
-
-uint16_t VoltageFastBuffer[FAST_BUFFER_SIZE];
-uint16_t CurrentFastBuffer[FAST_BUFFER_SIZE];
-uint16_t RefVoltFastBuffer[FAST_BUFFER_SIZE];
+static __IO uint16_t ADC_Buffer[ADC_BUFFER_SIZE];
+static __IO uint16_t VoltageFastBuffer[FAST_BUFFER_SIZE];
+static __IO uint16_t CurrentFastBuffer[FAST_BUFFER_SIZE];
 
 /* Private constants ---------------------------------------------------------*/
 __near __no_init const unsigned char Factory_VREFINT @ 0x4910;
 
 /* Private function prototypes -----------------------------------------------*/
-static void ADC_Config(void);
-static void DMA_Config(void);
-static void TIM2_Config(void);
+static void ADC_ConfigADC(void);
+static void ADC_ConfigDMA(void);
+static void ADC_ConfigTIM2(void);
 
 /* Private functions ---------------------------------------------------------*/
 
@@ -40,16 +58,16 @@ static void TIM2_Config(void);
   * @param  None
   * @retval None
   */
-void Init_ADC(void)
+void ADC_Config(void)
 {
     /* ADC configuration */
-    ADC_Config();
+    ADC_ConfigADC();
 
     /* DMA configuration */
-    DMA_Config();
+    ADC_ConfigDMA();
 
     /* TIM2 configuration */
-    TIM2_Config();
+    ADC_ConfigTIM2();
 }
 
 /**
@@ -57,7 +75,7 @@ void Init_ADC(void)
   * @param  None
   * @retval None
   */
-static void ADC_Config(void)
+static void ADC_ConfigADC(void)
 {
     /* Enable ADC1 clock */
     CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
@@ -78,10 +96,12 @@ static void ADC_Config(void)
     ADC_ChannelCmd(ADC1, CURRENT_CHANNEL, ENABLE);
     ADC_SchmittTriggerConfig(ADC1, CURRENT_CHANNEL, DISABLE);
 
+#ifdef ADC_MEASURE_REF_VOLT
     /* ADC Voltage Reference */
     ADC_VrefintCmd(ENABLE);
     /* Enable ADC1 Vrefint Channel */
     ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE);
+#endif // ADC_MEASURE_REF_VOLT
 
     /* Enable ADC1 DMA requests*/
     ADC_DMACmd(ADC1, ENABLE);
@@ -95,7 +115,7 @@ static void ADC_Config(void)
   * @param  None
   * @retval None
   */
-static void DMA_Config(void)
+static void ADC_ConfigDMA(void)
 {
     /* Enable DMA1 clock */
     CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);
@@ -127,7 +147,7 @@ static void DMA_Config(void)
   * @param  None
   * @retval None
   */
-static void TIM2_Config(void)
+static void ADC_ConfigTIM2(void)
 {
     /* Enable TIM2 clock */
     CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
@@ -145,6 +165,88 @@ static void TIM2_Config(void)
     TIM2_Cmd(ENABLE);
 }
 
+/**
+  * @brief DMA1 channel0 and channel1 Interrupt routine.
+  * @param  None
+  * @retval None
+  */
+INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler,2)
+{
+    static uint8_t idx = 0;
+
+    VoltageFastBuffer[idx] = ADC_Buffer[0];
+    CurrentFastBuffer[idx] = ADC_Buffer[1];
+
+    idx ++;
+    if(idx >= FAST_BUFFER_SIZE) {
+        idx = 0;
+    }
+
+    /* Clear IT Pending Bit */
+    DMA1_Channel0->CSPR &= (uint8_t)~(uint8_t)(DMA1_IT_TC0 & (uint8_t)0x06);
+}
+
+/**
+  * @brief  Return average values from fast buffers
+  * @param  None
+  * @retval Latest_Voltage
+  */
+uint16_t * ADC_GetValues(void) {
+  static uint16_t avgVal[ADC_BUFFER_SIZE];
+  uint32_t volt=0, curr=0;
+  uint16_t middle, shunt_volt;
+  uint8_t i;
+
+  /* Summarize buffers values */
+  for(i=0;i<FAST_BUFFER_SIZE;i++){
+    volt += VoltageFastBuffer[i];
+    curr += CurrentFastBuffer[i];
+  }
+
+  /* Попытка оверсемплинга, чтобы сделать шаг ~1мВ
+     делим на 8, умножаем на опорное напряжение, умножаем на входной делитель
+     и делим на (12 бит АЦП * 8). */
+
+  volt >>= 3;
+  volt *= ADC_REF;
+  volt *= ADC_VOLT_K;
+  volt /= ADC_ODIV;
+
+  /* получаем среднее по току, затем фильтруем */
+  curr >>= 6;
+  middle = curr + 8;
+  middle &= 0xFFF0;
+  curr = 0;
+  uint8_t cnt = 0;
+  uint16_t tmp;
+   for(i=1; i<FAST_BUFFER_SIZE; i+=2){
+    tmp = CurrentFastBuffer[i];
+    tmp += 8;
+    tmp &= 0xFFF0;
+    if(tmp == middle){
+      cnt ++;
+      curr += CurrentFastBuffer[i];
+    }
+   }
+
+  /* Усредняем преобразованный результат
+     и переводим код АЦП в милиамперы */
+  if(cnt > 0){
+    curr /= cnt;
+  } else {
+    curr = middle;
+  }
+  curr *= ADC_REF;
+  curr /= ADC_DIV;
+
+  shunt_volt = curr / ADC_CURR_K;
+  volt -= shunt_volt;
+
+  avgVal[0] = (uint16_t)volt;
+  avgVal[1] = (uint16_t)curr;
+
+  return avgVal;
+}
 
 /**
   * @}

+ 10 - 16
lib/adc.h

@@ -18,25 +18,19 @@
 
 /* Exported types ------------------------------------------------------------*/
 /* Exported defines ----------------------------------------------------------*/
-#define VOLTAGE_CHANNEL     ADC_Channel_17
-#define CURRENT_CHANNEL     ADC_Channel_18
-#define ADC1_DR_ADDRESS     ((uint16_t)0x5344)
-#define ADC_BUFFER_SIZE     ((uint8_t) 3)
-#define ADC_BUFFER_ADDRESS  ((uint16_t)(&ADC_Buffer))
-
-#define FAST_BUFFER_SIZE    ((uint8_t) 16)
-/* ADC_RATIO = (( 3.3 * 1000 * 1000 ) + 2048 ) / 4095 */
-#define ADC_RATIO       806UL
-#define ADC_VOLT_RATIO  8864UL
-
-// (×àñòîòà ÌÊ (16 ÌHz) / Ïðåääåëèòåëü òàéìåðà (32) * Íóæíîå âðåìÿ â ñåêóíäàõ (0.00125)) - 1
-#define TIM_PERIOD          ((uint16_t)624)
-#define TIM_PRESCALER       TIM2_Prescaler_32
-
 /* Exported constants --------------------------------------------------------*/
+#define ADC_BUFFER_SIZE     ((uint8_t)2)
+#define FAST_BUFFER_SIZE    ((uint8_t)64)
+
 /* Exported macro ------------------------------------------------------------*/
+/* Exported variables --------------------------------------------------------*/
+extern __IO uint16_t ADC_Buffer[];
+extern __IO uint16_t VoltageFastBuffer[];
+extern __IO uint16_t CurrentFastBuffer[];
+
 /* Exported functions ------------------------------------------------------- */
-void Init_ADC(void);
+void ADC_Config(void);
+uint16_t * ADC_GetValues(void);
 
 #endif /* __ADC_H */
 

+ 5 - 5
lib/max7219.c

@@ -18,7 +18,7 @@
 #define SPI_MOSI        GPIO_Pin_6
 #define SPI_PINS        (SPI_SCK|SPI_MOSI)
 
-void MAX7219_Init(void) {
+void MAX7219_Config(void) {
     SPI_DeInit(SPI1);
     /* Enable clock for SPI */
     CLK_PeripheralClockConfig(CLK_Peripheral_SPI1, ENABLE);
@@ -34,10 +34,10 @@ void MAX7219_Init(void) {
     SPI_Cmd(SPI1, ENABLE);
 
     /* Настройка MAX71219 */
-	MAX7219_WriteData(DecodeMode, 0x00);            // все без BCD декодирования
-	MAX7219_WriteData(ScanLimit, MAX7219_DIGITS);   // сколько цифр используем
-	MAX7219_WriteData(Intensity, MAX7219_BRIGHT);   // яркость из 16
-	MAX7219_WriteData(Power, MAX7219_ON);           // включили питание
+	MAX7219_WriteData(RegDecodeMode, 0x00);            // все без BCD декодирования
+	MAX7219_WriteData(RegScanLimit, MAX7219_DIGITS);   // сколько цифр используем
+	MAX7219_WriteData(RegIntensity, MAX7219_BRIGHT);   // яркость из 16
+	MAX7219_WriteData(RegPower, MAX7219_ON);           // включили питание
 
 }
 

+ 19 - 19
lib/max7219.h

@@ -27,7 +27,7 @@
 #define SEG_E			6
 #define SEG_F			0
 #define SEG_G			7
-#define SEG_DP			4
+#define SEG_DP		4
 
 // symbols
 // Для BCD
@@ -69,24 +69,24 @@
 #define MAX7219_DIGITS  7
 
 /* Exported types ------------------------------------------------------------*/
-typedef enum {
-    NoOp        = 0x00,
-    Digit0      = 0x03,
-    Digit1      = 0x08,
-    Digit2      = 0x02,
-    Digit3      = 0x01,
-    Digit4      = 0x07,
-    Digit5      = 0x04,
-    Digit6      = 0x06,
-    Digit7      = 0x05,
-    DecodeMode  = 0x09,
-    Intensity   = 0x0A,
-    ScanLimit   = 0x0B,
-    Power       = 0x0C,
-    Test        = 0x0F
+typedef enum _max7219_reg {
+    RegNoOp        = 0x00,
+    RegDigit0      = 0x03,
+    RegDigit1      = 0x08,
+    RegDigit2      = 0x02,
+    RegDigit3      = 0x01,
+    RegDigit4      = 0x07,
+    RegDigit5      = 0x04,
+    RegDigit6      = 0x06,
+    RegDigit7      = 0x05,
+    RegDecodeMode  = 0x09,
+    RegIntensity   = 0x0A,
+    RegScanLimit   = 0x0B,
+    RegPower       = 0x0C,
+    RegTest        = 0x0F
 } max7219_reg_t;
 
-typedef enum {
+typedef enum _max7219_seg {
     SegA    = SEG_A,
     SegB    = SEG_B,
     SegC    = SEG_C,
@@ -97,7 +97,7 @@ typedef enum {
     SegDP   = SEG_DP,
 } max7219_seg_t;
 
-typedef enum {
+typedef enum _max7219_sym {
     Sym_0        = SYM_0,
     Sym_1        = SYM_1,
     Sym_2        = SYM_2,
@@ -130,7 +130,7 @@ typedef enum {
 /* Exported macro ------------------------------------------------------------*/
 /* Exported variables --------------------------------------------------------*/
 /* Exported functions --------------------------------------------------------*/
-void MAX7219_Init(void);
+void MAX7219_Config(void);
 void MAX7219_WriteData(max7219_reg_t reg, uint8_t data);
 
 #endif /* __MAX7219_H */

+ 1 - 1
lib/rtos.c

@@ -15,7 +15,7 @@ static __IO uint16_t TimingDelay;
 /******************************************************************************************
  * Èíèöèàëèçàöèÿ ÐÒÎÑ, âðåìÿ òèêà - 1 ìñ
  */
-inline void RTOS_Init()
+inline void RTOS_Config()
 {
   /*
   TIM4 configuration:

+ 1 - 1
lib/rtos.h

@@ -50,7 +50,7 @@ typedef struct task
 /******************************************************************************************
  * Ïðîòîòèïû ôóêíöèé
  */
-void RTOS_Init (void);
+void RTOS_Config (void);
 void RTOS_SetTask (void (*taskFunc)(void), uint16_t taskDelay, uint16_t taskPeriod);
 void RTOS_DeleteTask (void (*taskFunc)(void));
 void RTOS_DispatchTask (void);

+ 140 - 115
src/main.c

@@ -35,6 +35,8 @@
 #define LED_GREEN_PORT  GPIOB
 #define LED_GREEN_PIN   GPIO_Pin_7
 
+#define VALUES_BUFFER_SIZE  10
+
 /* Private macro -------------------------------------------------------------*/
 #define LED_RED_ON      LED_RED_PORT->ODR &= (uint8_t)(~LED_RED_PIN)
 #define LED_RED_OFF     LED_RED_PORT->ODR |= LED_RED_PIN
@@ -44,54 +46,36 @@
 /* Private constant ----------------------------------------------------------*/
 // перевод числа 0-7 в номер индикатора
 static const max7219_reg_t dig[8] = {
-	Digit0,
-	Digit1,
-	Digit2,
-	Digit3,
-	Digit4,
-	Digit5,
-	Digit6,
-	Digit7
+	RegDigit0, RegDigit1, RegDigit2, RegDigit3,
+	RegDigit4, RegDigit5, RegDigit6, RegDigit7
 };
 
 // перевод значения 0x00 - 0x0F в код индикатора
 static const max7219_sym_t num[16] = {
-	Sym_0,
-	Sym_1,
-	Sym_2,
-	Sym_3,
-	Sym_4,
-	Sym_5,
-	Sym_6,
-	Sym_7,
-	Sym_8,
-	Sym_9,
-	Sym_A,
-	Sym_b,
-	Sym_C,
-	Sym_d,
-	Sym_E,
-	Sym_F
+	Sym_0, Sym_1, Sym_2, Sym_3, Sym_4, Sym_5, Sym_6, Sym_7,
+	Sym_8, Sym_9, Sym_A, Sym_b, Sym_C, Sym_d, Sym_E, Sym_F
 };
 
 /* Private variables ---------------------------------------------------------*/
-uint16_t Voltage = 0;
-uint16_t Current = 0;
-uint16_t RefVolt = 0;
+static uint16_t bufVoltage[VALUES_BUFFER_SIZE];
+static uint16_t bufCurrent[VALUES_BUFFER_SIZE];
 
-extern uint16_t VoltageFastBuffer[];
-extern uint16_t CurrentFastBuffer[];
-extern uint16_t RefVoltFastBuffer[];
+/* averaged values for 1 sek */
+static uint16_t Voltage;
+static uint16_t Current;
+static uint32_t Power;
+static uint32_t CapacityAH = 0;
+static uint32_t CapacityWH = 0;
 
 /* Private function prototypes -----------------------------------------------*/
 static void GPIO_Config(void);
 static void CLK_Config(void);
 
 /* RTOS function prototypes -----------------------------------------------*/
-static void ShowTopLineV(void);
-static void ShowTopLineC(void);
-static void ShowBotLine(void);
-static void ProcessFastBuffer(void);
+static void getADCValues(void);
+static void calculateValues(void);
+static void showTopLineU(void);
+static void showBotLineI(void);
 
 /* Private functions ---------------------------------------------------------*/
 
@@ -109,115 +93,156 @@ void main(void)
   GPIO_Config();
 
   /* RTOS Configuration */
-  RTOS_Init();
+  RTOS_Config();
 
    /* ADC Configuration and start */
-  Init_ADC();
+  ADC_Config();
 
   /* MAX7219 Configuration */
-  MAX7219_Init();
+  MAX7219_Config();
 
   /* ROTS tasks */
-  RTOS_SetTask(ProcessFastBuffer,0,100);
-  RTOS_SetTask(ShowTopLineV,101,4000);
-  RTOS_SetTask(ShowTopLineC,2101,4000);
-  RTOS_SetTask(ShowBotLine,101,100);
+  RTOS_SetTask(getADCValues,100,100);
+  RTOS_SetTask(calculateValues,101,1000);
+  RTOS_SetTask(showTopLineU,102,250);
+  RTOS_SetTask(showBotLineI,103,250);
 
   /* Infinite loop */
-  while (1)
-  {
+  while (1) {
       RTOS_DispatchTask();
-      Delay(1);
+      wfi();
   }
 }
 
-/*
- * Фильтрация и усреднение данных из быстрого буфера,
- * вычесление значений, перенос в медленный буфер.
- */
-static void ProcessFastBuffer(void){
-    uint16_t volt=0, curr=0, ref=0;
-
-    /* Summarize buffers values */
-    uint8_t i;
-    for(i=0;i<FAST_BUFFER_SIZE;i++){
-        volt += VoltageFastBuffer[i];
-        curr += CurrentFastBuffer[i];
-        ref += RefVoltFastBuffer[i];
-    }
-
-    /* Calculate voltage value*/
-    Voltage = ((volt / FAST_BUFFER_SIZE) * ADC_VOLT_RATIO) / 1000;
-
-    /* Calculate current value*/
-    Current = ((curr / FAST_BUFFER_SIZE) * ADC_RATIO) / 1000;
-
-    /* Calculate reference voltage value*/
-    RefVolt = ((ref / FAST_BUFFER_SIZE) * ADC_RATIO) / 1000;
+/**
+  * Забираем обработанные данные из быстрого буфера
+  * и складываем в медленный.
+  */
+static void getADCValues(void) {
+  static uint8_t idxVal=0;
+  uint16_t * avgVal;
+
+  avgVal = ADC_GetValues();
+
+  bufVoltage[idxVal] = *avgVal;
+  bufCurrent[idxVal] = *(avgVal + 1);
+
+  idxVal ++;
+  if (idxVal == VALUES_BUFFER_SIZE) {
+    idxVal = 0;
+  }
 }
 
-/*
- * Output to top indicator line
- */
-static void ShowTopLineV(void){
-    uint8_t voltage1000 = 0;
-    uint8_t voltage100 = 0;
-    uint8_t voltage10 = 0;
-    uint8_t voltage1 = 0;
+/**
+  * Average values from slow buffer.
+  * Calculate Power, Capacitance IH and WH.
+  */
+static void calculateValues(void) {
+  uint8_t i;
+  uint16_t c=0;
+  uint32_t v=0;
+
+  for (i=0; i<VALUES_BUFFER_SIZE; i++) {
+    v += bufVoltage[i];
+    c += bufCurrent[i];
+  }
 
-    /* Thousands voltage value*/
-    voltage1000 = (uint8_t)(Voltage / 1000);
-    /* Hundreds voltage value */
-    voltage100 = (uint8_t)((Voltage % 1000) / 100);
-    /* Tens voltage value */
-    voltage10 = (uint8_t)((Voltage % 100 ) / 10);
-    /* Ones voltage value */
-    voltage1 = (uint8_t)(Voltage % 10);
+  Current = (c + (VALUES_BUFFER_SIZE/2)) / VALUES_BUFFER_SIZE;
+  Voltage = (v + (VALUES_BUFFER_SIZE/2)) / VALUES_BUFFER_SIZE;
 
-    LED_RED_ON;
+  Power = ((Voltage * Current) + 500) / 1000;
 
-    MAX7219_WriteData(dig[0], num[voltage1000]);
-    MAX7219_WriteData(dig[1], num[voltage100]);
-    MAX7219_WriteData(dig[2], num[voltage10]);
-    MAX7219_WriteData(dig[3], num[voltage1]);
+  CapacityAH += Current;
+  CapacityWH += Power;
 }
 
-static void ShowTopLineC(void){
-    LED_RED_OFF;
-    uint8_t tmp = Current / 1000;
+/**
+  * Output voltage values to top indicator
+  */
+static void showTopLineU(void) {
+  uint32_t vlt = 0;
+  uint8_t tmp;
+
+  for (tmp=0; tmp<VALUES_BUFFER_SIZE; tmp++) {
+    vlt += bufVoltage[tmp];
+  }
+  vlt /= VALUES_BUFFER_SIZE;
+
+//  LED_RED_ON;
+
+  if(vlt >= 10000){
+    /* Tens Thousands voltage value*/
+    tmp = (uint8_t)(vlt / 10000);
+    vlt %= 10000;
     MAX7219_WriteData(dig[0], num[tmp]);
-    tmp = (Current % 1000) / 100;
-    MAX7219_WriteData(dig[1], num[tmp]);
-    tmp = (Current % 100) / 10;
+    /* Thousands voltage value*/
+    tmp = (uint8_t)(vlt / 1000);
+    vlt %= 1000;
+    MAX7219_WriteData(dig[1], (num[tmp] | SYM_DOT));
+    /* Hundreds voltage value */
+    tmp = (uint8_t)(vlt / 100);
+    vlt %= 100;
     MAX7219_WriteData(dig[2], num[tmp]);
-    tmp = Current % 10;
+    /* Tens voltage value */
+    tmp = (uint8_t)(vlt / 10);
     MAX7219_WriteData(dig[3], num[tmp]);
-}
-
-/*
- * Output to bottom indicator line
- */
-static void ShowBotLine(void){
-    uint8_t voltage1000 = 0;
-    uint8_t voltage100 = 0;
-    uint8_t voltage10 = 0;
-    uint8_t voltage1 = 0;
-
+  } else {
     /* Thousands voltage value*/
-    voltage1000 = (uint8_t)(RefVolt / 1000);
+    tmp = (uint8_t)(vlt / 1000);
+    vlt %= 1000;
+    MAX7219_WriteData(dig[0], (num[tmp] | SYM_DOT));
     /* Hundreds voltage value */
-    voltage100 = (uint8_t)((RefVolt % 1000) / 100);
+    tmp = (uint8_t)(vlt / 100);
+    vlt %= 100;
+    MAX7219_WriteData(dig[1], num[tmp]);
     /* Tens voltage value */
-    voltage10 = (uint8_t)((RefVolt % 100 ) / 10);
+    tmp = (uint8_t)(vlt / 10);
+    vlt %= 10;
+    MAX7219_WriteData(dig[2], num[tmp]);
     /* Ones voltage value */
-    voltage1 = (uint8_t)(RefVolt % 10);
-
-    MAX7219_WriteData(dig[4], num[voltage1000]);
-    MAX7219_WriteData(dig[5], num[voltage100]);
-    MAX7219_WriteData(dig[6], num[voltage10]);
-    MAX7219_WriteData(dig[7], num[voltage1]);
+    MAX7219_WriteData(dig[3], num[(uint8_t)vlt]);
+  }
 }
 
+/**
+  * Output current values to bottom indicator
+  */
+static void showBotLineI(void){
+//  LED_RED_OFF; // индикация режима
+  uint16_t crnt = 0;
+  uint8_t tmp;
+
+  for (tmp=0; tmp<VALUES_BUFFER_SIZE; tmp++) {
+    crnt += bufCurrent[tmp];
+  }
+  crnt /= VALUES_BUFFER_SIZE;
+
+  if (crnt >= 1000) {
+    tmp = crnt / 1000;
+    crnt %= 1000;
+  } else {
+    tmp = 0;
+  }
+  MAX7219_WriteData(dig[4], (num[tmp] | SYM_DOT));
+
+  if (crnt >= 100) {
+    tmp = crnt / 100;
+    crnt %= 100;
+  } else {
+    tmp = 0;
+  }
+  MAX7219_WriteData(dig[5], num[tmp]);
+
+  if (crnt >= 10) {
+    tmp = crnt / 10;
+    crnt %= 10;
+  } else {
+    tmp = 0;
+  }
+  MAX7219_WriteData(dig[6], num[tmp]);
+
+  MAX7219_WriteData(dig[7], num[crnt]);
+}
 
 /**
   * @brief  Configure GPIO for button available on the VAPC board

+ 2 - 19
src/stm8l15x_it.c

@@ -28,7 +28,6 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "stm8l15x_it.h"
-#include "adc.h"
 
 /** @addtogroup STM8L15x_StdPeriph_Template
   * @{
@@ -38,11 +37,6 @@
 /* Private define ------------------------------------------------------------*/
 /* Private macro -------------------------------------------------------------*/
 /* Private variables ---------------------------------------------------------*/
-extern uint16_t VoltageFastBuffer[];
-extern uint16_t CurrentFastBuffer[];
-extern uint16_t RefVoltFastBuffer[];
-extern uint16_t ADC_Buffer[];
-
 /* Private function prototypes -----------------------------------------------*/
 /* Private functions ---------------------------------------------------------*/
 /* Public functions ----------------------------------------------------------*/
@@ -92,22 +86,11 @@ INTERRUPT_HANDLER(FLASH_IRQHandler,1)
   * @param  None
   * @retval None
   */
+/*
 INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler,2)
 {
-    static uint8_t i = 0;
-
-    VoltageFastBuffer[i] = ADC_Buffer[0];
-    CurrentFastBuffer[i] = ADC_Buffer[1];
-    RefVoltFastBuffer[i] = ADC_Buffer[2];
-
-    i ++;
-    if(i >= FAST_BUFFER_SIZE) {
-        i = 0;
-    }
-
-    /* Clear IT Pending Bit */
-    DMA1_Channel0->CSPR &= (uint8_t)~(uint8_t)(DMA1_IT_TC0 & (uint8_t)0x06);
 }
+*/
 /**
   * @brief DMA1 channel2 and channel3 Interrupt routine.
   * @param  None