Гyдвин, волшебник (20.11.2017 15:23, просмотров: 880) ответил Гyдвин на Вступил, йопть, в STM8. Сразу такая граблЯ - пин PD1 порта D после сброса используется для SWIM. Любая запись в регистр DDR порта, вырубает отладку. Бит 1, естественно,=0. Извечный русский вопрос к уже вступившим: Кто виноват и что делать? Отладка
Вступил. Вполне даже неплох этот STM8, если прикрыть глаза на французские шалости. Понравилась отладка. Шустрая, много точек останова. Даже в таком мелком чипе. Отладчики MSP, AVR и PIC отдыхают. Внутри история болезни и стационарного лечения ;) Может кому пригодится:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Пациент - китайский идикатор напряжения и тока на STM8 в ssop20
// Место жительства: https://ru.aliexpr …r-online-shopping.html
//
// Анамнез: бред, навязчибые попытки показывать "направление на Пентагон","погоду за бортом" вместо исполнения штатных обязанностей.
//
// Дагноз: идиотские делители в каналах измерения, использование малого участка диапазона встроенного АЦП.
// Положительные моменты - пациет немного кушает при достаточно ярком индикаторе, имеет стабилизатор/опору с неплохими характеристиками.
//
// Операционное вмешательство:
// Пересадка LM358 на r2r output MCP602 для увеличения диапазона выходного сигнала
// Замена/подгонка резисторов в делителе напряжения и обратной связи ОУ токового канала
// с целью нормировать входные сигналы к полному диапазону АЦП.
//
// Консервативное реанимационное лечение:
// Не пинать! Интерн провел первую операцию на STM8.
// Говнокодие, ибо "шармоватое" распределение аж 4 портов в 16 пин в STM8S003F3 не позволяет "изобразить красиво"
// А может просто интерн не умеет их готовить - STM еще те затейники :)
// Ну и что китайцы выродили/развели, то и приходится лечить...
// Не пользовал прерывания. Ини пациету они в этом случае нафиг не нужны.
// Так проще выровнять яркость свечения знакомест индикаторов (красные/синие, нагрузочные способности портов).
// Инструменты:
// IAR v 1.4. Более старшие не ставятся на XP :(
// Оптимизация LOW или Medium.
// При оптимизации "High" IAR v1.4 делает даже этот простенький линейный код неработоспособным. Пациент дохнет :)
//
// Эпикриз: пациенту стало значительно лучше.
//
// Амбулаторное лечение:
// Обратиться с светилам медицины ST для дальнейших консультаций и назначений.
// Есть возможность переучить для другого рода деятельности.
// Например, после несложной хирургии и лечения использовать как дешевый законченный встраиваемый индикатор
// c последовательным интерфейсом. Ибо RX,TX uart разведены на разъем.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "stm8s.h"
#include <stdio.h>
//для выравнивания яркости знакомест
#define DELAY 600 // время индикации символа разрядов 1..3
#define DELAY1 500 // время индикации символа разрядов 4..5
#define DELAY2 800 // время индикации символа разряда 6
#define N_AVERAGE 256 // количество замеров ADC для усреднения (д.б. кратно 2 и желательно степень 2)
unsigned int cnt_adc; //
char disp[8]=" 00000";
unsigned long adc_U;// сумма adc U для усреднения
unsigned long adc_I;// сумма adc I для усреднения
unsigned int tmp_i;// для процедуры калибровки смещения ОУ в канале измерения тока
unsigned int sav_i;// для установки позиции точки индикатора тока
uint16_t *zero_I = (uint16_t *)0x4000; // калибровка начального смещения ОУ тока в EEPROM
void delay(long t)
{
long i;
for (i = 0;i < t;i++);
}
void work_adc(void)
{
unsigned int tmp;
ADC1->CSR = 0x04; // AIN4 (PD3) Канал напряжения
ADC1->CR1 |= 0x01; // start conversion
while (!(ADC1->CSR & 0x80)); // wait for end of conversion
tmp= ADC1->DRL;
tmp |= (ADC1->DRH << 8);
adc_U+=tmp;
ADC1->CSR = 0x03; // AIN3 (PD2) Канал тока
ADC1->CR1 |= 0x01;// start conversion
while (!(ADC1->CSR & 0x80)); // wait for end of conversion
tmp= ADC1->DRL;
tmp |= (ADC1->DRH << 8);
tmp_i=tmp;// в tmp_i останется "сырое" значение тока после выполнения функции
// компенсация смещения ОУ канала измерения тока
if (tmp < *zero_I) tmp=0;
else tmp= tmp - *zero_I;
adc_I+=tmp;
cnt_adc++;
if (cnt_adc==N_AVERAGE)
{
cnt_adc=0;
adc_U= adc_U/N_AVERAGE; // вычисляем среднее напряжения
adc_U/=4; //масштабируем значение напряжения для вывода на индикатор // 12V = 480adc, max 25.575V = 1023adc
adc_I= adc_I/(N_AVERAGE/2); // вычисляем среднее тока + масштабируем + некое повышение разрядности для вывода на индикатор. 10A = 500adc*2
sav_i=adc_I; // запомним тасштабированное значение тока
sprintf(disp,"%03lu%03lu", adc_U,adc_I);
if (disp[0]=='0') disp[0]=' '; //удалим незначащий нуль
adc_I=0; // обнулим для следуюшего цикла
adc_U=0;
}
}
void out_7led_dig(char numb_dig) // вывод очередного символа в 7LED из строки disp
{
GPIOC->ODR&= ~(1<<5); //PC5 (DP) // сотрем точку
if (numb_dig == 1) GPIOC->ODR|= (1<<5); //PC5 (DP) // выведем точку (напряжение)
if ((sav_i < 1000)&&(numb_dig == 3)) GPIOC->ODR|= (1<<5); //PC5 (DP) // выведем точку (ток < 10А)
if ((sav_i > 999)&&(numb_dig == 4)) GPIOC->ODR|= (1<<5); //PC5 (DP) // выведем точку (ток >= 10А)
switch (disp[numb_dig])
{
case '0':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR|= (1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR&= ~(1<<2); // PA2 (G)
break;
case '1':
GPIOD->ODR&= ~(1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR&= ~(1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR&= ~(1<<4); // PC4 (F)
GPIOA->ODR&= ~(1<<2); // PA2 (G)
break;
case '2':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR&= ~(1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR|= (1<<7); // PC7 (E)
GPIOC->ODR&= ~(1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '3':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR&= ~(1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '4':
GPIOD->ODR&= ~(1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR&= ~(1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '5':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR&= ~(1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '6':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR&= ~(1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR|= (1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '7':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR&= ~(1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR&= ~(1<<4); // PC4 (F)
GPIOA->ODR&= ~(1<<2); // PA2 (G)
break;
case '8':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR|= (1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
case '9':
GPIOD->ODR|= (1<<1); // PD1 (A)
GPIOA->ODR|= (1<<3); // PA3 (B)
GPIOC->ODR|= (1<<3); // PC3 (C)
GPIOC->ODR|= (1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR|= (1<<4); // PC4 (F)
GPIOA->ODR|= (1<<2); // PA2 (G)
break;
default:
GPIOD->ODR&= ~(1<<1); // PD1 (A)
GPIOA->ODR&= ~(1<<3); // PA3 (B)
GPIOC->ODR&= ~(1<<3); // PC3 (C)
GPIOC->ODR&= ~(1<<6); // PC6 (D)
GPIOC->ODR&= ~(1<<7); // PC7 (E)
GPIOC->ODR&= ~(1<<4); // PC4 (F)
GPIOA->ODR&= ~(1<<2); // PA2 (G)
break;
}
}
void main(void)
{
CLK->CKDIVR = 0x00; // 16MHz
CFG->GCR |= CFG_GCR_SWD; // отключим SWIM
// Set ADC
ADC1->CR1 = 0x40; //Fadc = Fmaster/8 = 2MHz
ADC1->CR2 = 0x08; //Right alignement
ADC1->CR1 |= 0x01; // ADC on
GPIOD->CR1|= (1<<6); // подтянем PD6 к VDD (это контакт перемычки)
delay(100); // задержка стабилизации ADC
// процедура калибровки смещения ОУ канала измерения тока при включении
if (!(GPIOD->IDR & (1<<6))) // если установлена перемычка (как в китайском оригинале) при включении, запоминаем в EEPROM смещение ОУ "zero_I". При отсутствии тока!
{
work_adc();
work_adc();
FLASH->DUKR = 0xAE;
FLASH->DUKR = 0x56;
*zero_I=tmp_i;
delay(90000);
while (!(GPIOD->IDR & (1<<6))) delay(10000);
IWDG->KR = IWDG_KEY_ENABLE; // Пересброс по WDT
while ( 1 );
}
// Set GPIO
GPIOB->DDR = 0xFF;
GPIOB->CR1 = 0xFF;
GPIOA->DDR = 0xFF;
GPIOA->CR1 = 0xFF;
GPIOC->DDR = 0xFF;
GPIOC->CR1 = 0xFF;
GPIOD->DDR = 0x72; // 0111 0010 // PD3,PD2 - вxоды ADC
GPIOD->CR1 = 0x72; // 0111 0010 // PD3,PD2 - вxоды ADC
GPIOD->ODR|= (1<<4); // PD4 = 1 (0) // общие катоды всех знакомест 7LED (столбцы)
GPIOD->ODR|= (1<<6); // PD6 = 1 (1)
GPIOD->ODR|= (1<<5); // PD5 = 1 (2)
GPIOB->ODR|= (1<<5); // PB5 = 1 (3)
GPIOB->ODR|= (1<<4); // PB4 = 1 (4)
GPIOA->ODR|= (1<<1); // PA1 = 1 (5)
while (1) // цикл по знакоместам
{
//disp[0]
work_adc();
GPIOD->ODR&= ~(1<<4); // PD4 = 0
out_7led_dig(0);
delay(DELAY);
GPIOD->ODR|= (1<<4); // PD4 = 1
//disp[1]
work_adc();
GPIOD->ODR&= ~(1<<6); // PD6 = 0
out_7led_dig(1);
delay(DELAY);
GPIOD->ODR|= (1<<6); // PD6 = 1
//disp[2]
work_adc();
GPIOD->ODR&= ~(1<<5); // PD5 = 0
out_7led_dig(2);
delay(DELAY);
GPIOD->ODR|= (1<<5); // PD5 = 1
//disp[3]
work_adc();
GPIOB->ODR&= ~(1<<5); // PB5 = 0
out_7led_dig(3);
delay(DELAY1);
GPIOB->ODR|= (1<<5); // PB5 = 1
//disp[4]
work_adc();
GPIOB->ODR&= ~(1<<4); // PB4 = 0
out_7led_dig(4);
delay(DELAY1);
GPIOB->ODR|= (1<<4); // PB4 = 1
//disp[5]
work_adc();
GPIOA->ODR&= ~(1<<1); // PA1 = 0
out_7led_dig(5);
delay(DELAY2);
GPIOA->ODR|= (1<<1); // PA1 = 1
}
}