Добрый день, есть такое движение у автолюбителей - покупать некоторые отечественные автомобили как своего рода конструктор для взрослых, в том числе и для последующего передвижения на нем по бездорожью. Одним из доступных таких автомобилей, до недавнего времени был «УАЗ-Patriot». Не буду вдаваться, на что идут творческие люди и с какими компромиссами сталкиваются, опишу только конструкцию переключателя режима работы полно‑приводной трансмиссии с кнопками подогрева сидений (далее просто селектор раздатки). Конструкция вполне себе какая есть, но если к примеру вы модернизируете автомобиль для себя, бывает желание изменить схему функционирования этого узла под свои нужды - например дополнить системой изменения давления в шинах и что-либо еще. Для этого надо иметь схему селектора, и возможность изменять прошивку установленного там микроконтроллера.
Приведу нарисованную мной схему селектора, который попал мне в руки:

Схема не сложная, и в зависимости от комплектации, на плате могут отсутствовать некоторые компоненты. Компоненты можно приобрести и установить, но с микроконтроллером ситуация стандартная: прочитать нельзя, но запрограммировать можно. Следующая цель - создание своей прошивки. Микроконтроллер, который установлен в блоке - STM8S003F3, простой 8-битный, с очень малым потреблением тока и ценой. Поэтому купил отладочную плату с аналогичным микроконтроллером со встроенным программатором по шине SWIM, и еще плату для экспериментов с таким же микроконтроллером. Заодно скачал и установил необходимую среду разработки для этого класса микроконтроллеров (на Хабре есть статьи на это тему).
На плате блока есть контакты для подключения программатора к микроконтроллеру:
заодно подключимся к свободным пинам микроконтроллера для отладки:
вид
штатные бескорпусные реле не отличаются особой надежностью, их заменили на внешние, а дополнительные кнопки пришлось напаивать отгибая вывод корпуса.
Так как функции селектора довольно простые, то и код получился компактным:
файл stm8s_conf.h:
Hidden text
/** ****************************************************************************** * @file stm8s_conf.h * @author MCD Application Team * @version V2.0.0 * @date 25-February-2011 * @brief This file is used to configure the Library. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM8S_CONF_H #define __STM8S_CONF_H /* Includes ------------------------------------------------------------------*/ #include "stm8s.h" /* Uncomment the line below to enable peripheral header file inclusion */ #if defined(STM8S105) || defined(STM8S103) || defined(STM8S903) || defined (STM8AF626x) #include "stm8s_adc1.h" #endif /* (STM8S105) ||(STM8S103) || (STM8S903) || STM8AF626x*/ #if defined(STM8S208) || defined(STM8S207) || defined (STM8AF52Ax) || defined (STM8AF62Ax) #include "stm8s_adc2.h" #endif /* (STM8S208) || (STM8S207) || (STM8AF62Ax) || (STM8AF52Ax) */ #include "stm8s_awu.h" #include "stm8s_beep.h" #if defined (STM8S208) || defined (STM8AF52Ax) #include "stm8s_can.h" #endif /* STM8S208 || STM8AF52Ax */ #include "stm8s_clk.h" #include "stm8s_exti.h" #include "stm8s_flash.h" #include "stm8s_gpio.h" #include "stm8s_i2c.h" #include "stm8s_itc.h" #include "stm8s_iwdg.h" #include "stm8s_rst.h" #include "stm8s_spi.h" #include "stm8s_tim1.h" #ifndef STM8S903 #include "stm8s_tim2.h" #endif /* STM8S903 */ #if defined(STM8S208) || defined(STM8S207) ||defined(STM8S105) || defined (STM8AF52Ax) ||\ defined (STM8AF62Ax) || defined (STM8AF626x) #include "stm8s_tim3.h" #endif /* (STM8S208) ||defined(STM8S207) ||defined(STM8S105) */ #ifndef STM8S903 #include "stm8s_tim4.h" #endif /* STM8S903 */ #ifdef STM8S903 #include "stm8s_tim5.h" #include "stm8s_tim6.h" #endif /* STM8S903 */ #if defined(STM8S208) ||defined(STM8S207) ||defined(STM8S103) ||defined(STM8S903) ||\ defined (STM8AF52Ax) || defined (STM8AF62Ax) #include "stm8s_uart1.h" #endif /* STM8S208 || STM8S207 || STM8S103 ||STM8S903 || STM8AF52Ax || STM8AF62Ax */ #if defined (STM8S105) || defined (STM8AF626x) #include "stm8s_uart2.h" #endif /* STM8S105 || STM8AF626x */ #if defined(STM8S208) ||defined(STM8S207) || defined (STM8AF52Ax) || defined (STM8AF62Ax) #include "stm8s_uart3.h" #endif /* STM8S208 || STM8S207 || STM8AF52Ax || STM8AF62Ax */ #include "stm8s_wwdg.h" /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Uncomment the line below to expanse the "assert_param" macro in the Standard Peripheral Library drivers code */ //#define USE_FULL_ASSERT (1) /* Exported macro ------------------------------------------------------------*/ #ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval : None */ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */ #endif /* __STM8S_CONF_H */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
файл board.h:
Hidden text
//распиновка платы STM8S003F3P6 1kB RAM 128 EEPROM 8k Flash // // +---|___|---+ // PD4 o-| |-o PD3 // PD5 o-| |-o PD2 // PD6 o-| |-o PD1 // NRST o-| |-o PC7 // PA1 o-| |-o PC6 // PA2 o-| |-o PC5 // GND o-| |-o PC4 // 5V o-| |-o PC3 // 3.3V o-| |-o PB4 // PA4 o-| |-o PB5 // +-----------+ // //************************************************************************** //Подключения платы селектора: //PA1 - выход светодиод подключенного бака 2 //PA2 - никуда не подключен //PA3 - кнопка вход переключателя бака 1/2 //PB4 - кнопка вход PHEAT //PB5 - кнопка вход DHEAT //PC3 - выход реле/светодиод DHEAT //PC4 - вход ADC_IN2 напряжение питания блока (VCC = 5V) //PC5 - селектор вход 2H //PC6 - выход реле/светодиод PHEAT //PC7 - выход реле/светодиод подключенного бака 1 //PD1 - SWIM //PD2 - выход управления X1_3 //PD3 - выход управления X1_1 //PD4 - селектор вход 4S //PD5 - селектор вход 4L //PD6 - селектор вход 4H // //TIM4 8 - битный таймер для генерации прерывания 1 мСек // // делитель напряжения питания, входное напряжение -> вход ADC // 12V -> 2V // 18V -> 3V // ... // //тестовый светодиод RGB и кнопка //PC7(17) - B (реле бака) //PA2(6) - G test pin //PA1(5) - R (светодиод бака) //PA4 - кнопка SW7 // //состояние кнопок храним в EEPROM и восстанавливаем при включении питания //используемые адреса: // 0x00 - состояние кнопки подогрева водительского сиденья // 0x01 - состояние кнопки подогрева пассажирского сиденья // 0x03 - состояние кнопки переключателя бензобака // #ifndef __BOARD_H #define __BOARD_H #include "stm8s.h" //селектор раздатки ***** //входы #define S2H_PIN GPIO_PIN_5 #define S2H_PORT GPIOC #define S4H_PIN GPIO_PIN_6 #define S4H_PORT GPIOD #define S4L_PIN GPIO_PIN_5 #define S4L_PORT GPIOD #define S4S_PIN GPIO_PIN_4 #define S4S_PORT GPIOD //выходы #define OUT_2H_PIN GPIO_PIN_2 #define OUT_2H_PORT GPIOD #define OUT_4L_PIN GPIO_PIN_3 #define OUT_4L_PORT GPIOD //подогрев сидений ***** //входы #define D_KEY_PIN GPIO_PIN_5 #define D_KEY_PORT GPIOB #define P_KEY_PIN GPIO_PIN_4 #define P_KEY_PORT GPIOB //выходы: #define D_HEAT_PIN GPIO_PIN_3 #define D_HEAT_PORT GPIOC #define P_HEAT_PIN GPIO_PIN_6 #define P_HEAT_PORT GPIOC //напряжение питания ***** #define V_IN_PIN GPIO_PIN_4 #define V_IN_PORT GPIOC //топливный бак ***** //входы #define TANK_KEY_PIN GPIO_PIN_3 #define TANK_KEY_PORT GPIOA //выходы: #define TANK_R_PIN GPIO_PIN_7 #define TANK_R_PORT GPIOC #define TANK_LED_PIN GPIO_PIN_1 #define TANK_LED_PORT GPIOA //тестовый выход (не разведен на плате) #define TEST_PIN GPIO_PIN_2 #define TEST_PORT GPIOA #define START_EEPROM 0x4000 #define SIZE_EEPROM 0x80 #define D_HEAT_EEPROM 0x4000 #define P_HEAT_EEPROM 0x4001 #define T_EEPROM 0x4002 #define SEL_NO 0 #define SEL_2H 1 #define SEL_4H 2 #define SEL_4L 4 #define SEL_4S 8 #define SEL_TICK_ON 150 //сколько тиков (mS) накапливаем значение селектора #define SEL_TICK_LOCK 1000 //сколько тиков (mS) накапливаем значение для включения блокировки селектора #define KEY_NO 0 //состояние кнопки #define KEY_SET 1 #define VP_MIN 12000 //минимально напряжение (mV)активности подогрева сидений #define VP_GIST 500 //допустимый гистерезис (mV) void CLK_Configuration(void); void GPIO_Configuration(void); void Delay(uint16_t Cycles); void TIM4_Configuration(void); void ADC_Configuration(void); void BoardInit(void); void Loop(void); void SystemMS(void); void TestPin(uint8_t action); void ScanSelector(void); void SetTransferBox(uint8_t st,uint8_t lk); void LedStatus(uint8_t LedMode); void LedT(uint8_t action); void ScanKeyHeat(void); void StatusKeyHeat(void); void SetHeat(void); void StatusKeyTank(void); void ScanKeyTank(void); void SetTank(void); uint8_t ReadStatusEEPROM(char s); uint8_t WriteStatusEEPROM(char s,uint8_t st); //main extern uint16_t res_adc; #endif
Файл board.c:
Hidden text
#include "board.h" #include "stm8s.h" //-------------------------------------------------------- //переменные uint16_t s2h_cnt; //счетчик циклов для достоверного определения положения uint16_t s4h_cnt; //счетчик циклов для достоверного определения положения uint16_t s4l_cnt; //счетчик циклов для достоверного определения положения uint16_t s4s_cnt; //счетчик циклов для достоверного определения положения uint8_t tr_Lock; //признак режима блокировки uint8_t select_status;//положение селектора uint8_t p2h; uint8_t p4h; uint8_t p4l; uint8_t p4s; uint8_t key_d_cnt; //счетчик циклов для достоверного распознования нажатия uint8_t key_p_cnt; //счетчик циклов для достоверного распознования нажатия uint8_t key_t_cnt; //счетчик циклов для достоверного распознования нажатия uint8_t key_d_press; //признак нажатия кнопки uint8_t key_p_press; //признак нажатия кнопки uint8_t key_t_press; //признак нажатия кнопки uint8_t key_d_status; //статус рабочего состояния подогрева сиденья вод uint8_t key_p_status; //статус рабочего состояния подогрева сиденья пасс uint8_t key_t_status; //статус рабочего состояния переключателя бака uint8_t key_d_change; //блокировка изменения состояния статуса uint8_t key_p_change; //блокировка изменения состояния статуса uint8_t key_t_change; //блокировка изменения состояния статуса uint16_t LedDiv; //управление миганием светодиодом режима работы uint16_t LedMask; //-- uint16_t rolmask; //-- uint16_t rolcnt; //-- uint16_t rolbit; //-- uint8_t LedMode; //-- uint8_t workMode; //текущий рабочий режим uint32_t MyTimeOn; //текущее рабочее время uint32_t convAdc; //вспомогательная переменная для пересчета АЦП uint16_t vdc; //напряжение питания в милливольтах uint8_t heat_block; //блокировка подогрева из за низкого напряжения //-------------------------------------------------------- //настройка тактирования void CLK_Configuration(void) { /* Fmaster = 16MHz */ CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // Предделитель частоты тактирования процессора и периферии CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); } //-------------------------------------------------------- //настройка портов ввода вывода void GPIO_Configuration(void) { /* GPIOD reset */ GPIO_DeInit(GPIOA); GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOC); GPIO_DeInit(GPIOD); //Селектор ***** //выходы GPIO_Init(OUT_2H_PORT, OUT_2H_PIN, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(OUT_4L_PORT, OUT_4L_PIN, GPIO_MODE_OUT_PP_LOW_FAST); //входы GPIO_Init(S2H_PORT, S2H_PIN, GPIO_MODE_IN_FL_NO_IT); GPIO_Init(S4H_PORT, S4H_PIN, GPIO_MODE_IN_FL_NO_IT); GPIO_Init(S4L_PORT, S4L_PIN, GPIO_MODE_IN_FL_NO_IT); GPIO_Init(S4S_PORT, S4S_PIN, GPIO_MODE_IN_FL_NO_IT); //подогрев сидений ***** //выходы GPIO_Init(D_HEAT_PORT,D_HEAT_PIN,GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(P_HEAT_PORT,P_HEAT_PIN,GPIO_MODE_OUT_PP_LOW_FAST); //входы GPIO_Init(D_KEY_PORT, D_KEY_PIN, GPIO_MODE_IN_FL_NO_IT ); GPIO_Init(P_KEY_PORT, P_KEY_PIN, GPIO_MODE_IN_FL_NO_IT ); //топливный бак ***** //выходы GPIO_Init(TANK_R_PORT, TANK_R_PIN, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(TANK_LED_PORT, TANK_LED_PIN, GPIO_MODE_OUT_PP_LOW_FAST); //входы GPIO_Init(TANK_KEY_PORT, TANK_KEY_PIN, GPIO_MODE_IN_FL_NO_IT ); //тестовый выход (не разведен на плате) //выходы PA2 GPIO_Init(TEST_PORT, TEST_PIN, GPIO_MODE_OUT_PP_LOW_FAST); } //-------------------------------------------------------- //задержка по тактам //65535 -> 50mSec void Delay(uint16_t Cycles) { uint16_t NumberOfStart = Cycles; while(NumberOfStart != 0) { NumberOfStart--; } } //-------------------------------------------------------- //настройка таймера 4 на генерацию прерывания с частотой 1мСек void TIM4_Configuration(void) { //Включаем тактирование таймера CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE); // На всякий случай сбрасываем все настройки таймера TIM4_DeInit(); // настраиваем пределитель таймера на 256 и ограничиваем счет 124 TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124); //Разрешаем Прерывание таймера по переполнению TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); // Включаем счет TIM4_Cmd(ENABLE); } //-------------------------------------------------------- //инициализация ADC PC4 - ADC_IN2 //преобразовывать будем по запросу, ибо в цикле слишком грузит процессор void ADC_Configuration(void) { GPIO_Init(V_IN_PORT,V_IN_PIN,GPIO_MODE_IN_FL_NO_IT); //вход для ADC ADC1_DeInit(); ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_2, ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM,DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL2, DISABLE); ADC1_ITConfig(ADC1_IT_EOCIE ,ENABLE); } //-------------------------------------------------------- void BoardInit(void) { CLK_Configuration(); //настраиваем тактирование GPIO_Configuration(); //настраиваем GPIO TIM4_Configuration(); //настраиваем таймер4 ADC_Configuration(); //настраиваем ADC1 select_status = SEL_NO; s2h_cnt = 0; s4h_cnt = 0; s4l_cnt = 0; s4s_cnt = 0; tr_Lock = 0; workMode = 0; MyTimeOn = 0; LedDiv = 0; rolcnt = 0; rolmask = 1; LedMask = 0; LedMode = 0; key_d_cnt = 0; key_p_cnt = 0; key_t_cnt = 0; key_d_press = 0; key_p_press = 0; key_t_press = 0; key_d_change = 0; key_p_change = 0; key_t_change = 0; // надо сначала прочитать состояние из EEPROM и сделать соответствующие статусы key_d_status = ReadStatusEEPROM('d'); key_p_status = ReadStatusEEPROM('p'); key_t_status = ReadStatusEEPROM('t');; // vdc = 0; heat_block = 0; } //-------------------------------------------------------- //системное прерывание каждую миллисекунду //длительность 15uSec void SystemMS(void) { // TestPin(1); MyTimeOn ++; ScanSelector(); //сканируем селектор ScanKeyHeat(); //сканируем кнопки подогрева StatusKeyHeat(); //меняем статус кнопок подогрева ScanKeyTank(); //сканируем кнопку бака StatusKeyTank(); //меняем статус кнопки бака LedStatus(workMode); //управляем тестовым сигналом // TestPin(0); } //-------------------------------------------------------- //основной цикл программы, не в прерывании //цикл примерно 8mS, длительность 2uS void Loop(void) { //TestPin(1); Delay(11796); //примерно 9 mSec ADC1_StartConversion(); //примерно через 30 uSec готово преобразование Delay(1310); //примерно 1 mSec //ADC 10 разрядов ! //превращаем 0x3ff (1023) -> 30000mV -> 3ff * 29 //питание процессора 4,8 Вольта ! vdc = res_adc * 29; SetHeat(); SetTank(); //TestPin(0); } //-------------------------------------------------------- //управление тестовым выходом, PA2 void TestPin(uint8_t action) { if(action == 0) { GPIO_WriteLow(TEST_PORT, TEST_PIN); } else { GPIO_WriteHigh(TEST_PORT, TEST_PIN); } } //-------------------------------------------------------- //вызываем каждую миллисекунду //читаем состояние селектора, действимтельно только 1 положение void ScanSelector(void) { p2h = GPIO_ReadInputPin(S2H_PORT,S2H_PIN);//возвращает 0 или номер бита ! p4h = GPIO_ReadInputPin(S4H_PORT,S4H_PIN);//возвращает 0 или номер бита ! p4l = GPIO_ReadInputPin(S4L_PORT,S4L_PIN);//возвращает 0 или номер бита ! p4s = GPIO_ReadInputPin(S4S_PORT,S4S_PIN);//возвращает 0 или номер бита ! if((p2h == 0) && (p4h != 0) && (p4l != 0) && (p4s != 0)) { if(s2h_cnt > SEL_TICK_ON) { s2h_cnt = SEL_TICK_ON; select_status = SEL_2H; tr_Lock = 0; //выключаем блокировку workMode = 1; SetTransferBox(select_status,tr_Lock); } else { s2h_cnt ++; } s4h_cnt = 0; s4l_cnt = 0; s4s_cnt = 0; }else if((p2h != 0) && (p4h == 0) && (p4l != 0) && (p4s != 0)) { if(s4h_cnt > SEL_TICK_ON) { s4h_cnt = SEL_TICK_ON; select_status = SEL_4H; tr_Lock = 0; //выключаем блокировку workMode = 2; SetTransferBox(select_status,tr_Lock); } else { s4h_cnt ++; } s2h_cnt = 0; s4l_cnt = 0; s4s_cnt = 0; }else if((p2h != 0) && (p4h != 0) && (p4l == 0) && (p4s != 0)) { if(s4l_cnt > SEL_TICK_ON) { s4l_cnt = SEL_TICK_ON; select_status = SEL_4L; tr_Lock = tr_Lock; //не меняем пока блокировку workMode = 3; SetTransferBox(select_status,tr_Lock); } else { s4l_cnt ++; } s2h_cnt = 0; s4h_cnt = 0; s4s_cnt = 0; }else if((p2h != 0) && (p4h != 0) && (p4l != 0) && (p4s == 0)) { if(s4s_cnt > SEL_TICK_LOCK) { s4s_cnt = SEL_TICK_LOCK; select_status = SEL_4S; tr_Lock = 1; //включаем блокировку workMode = 4; SetTransferBox(select_status,tr_Lock); } else { s4s_cnt ++; } s2h_cnt = 0; s4h_cnt = 0; s4l_cnt = 0; }else { //в разрыве или сразу в двух положениях ничего не трогаем workMode = 0; s2h_cnt = 0; s4h_cnt = 0; s4l_cnt = 0; s4s_cnt = 0; } //покажем состояние блокировки if(tr_Lock == 1) { TestPin(1); //G } else { TestPin(0); //G } } //-------------------------------------------------------- //сканируем кнопки подогрева сидений void ScanKeyHeat(void) { //кнопка подогрева водительского сиденья if(GPIO_ReadInputPin(D_KEY_PORT,D_KEY_PIN) == 0) //возвращает 0 или номер бита ! { if(key_d_cnt > SEL_TICK_ON) { key_d_cnt = SEL_TICK_ON; key_d_press = 1; } else { key_d_cnt ++; } } else { key_d_press = 0; key_d_cnt = 0; } //кнопка подогрева пассажирского сиденья if(GPIO_ReadInputPin(P_KEY_PORT,P_KEY_PIN) == 0) //возвращает 0 или номер бита ! { if(key_p_cnt > SEL_TICK_ON) { key_p_cnt = SEL_TICK_ON; key_p_press = 1; } else { key_p_cnt ++; } } else { key_p_press = 0; key_p_cnt = 0; } } //-------------------------------------------------------- //сканируем кнопку бака void ScanKeyTank(void) { //кнопка переключения топливного бака if(GPIO_ReadInputPin(TANK_KEY_PORT,TANK_KEY_PIN) == 0) //возвращает 0 или номер бита ! { if(key_t_cnt > SEL_TICK_ON) { key_t_cnt = SEL_TICK_ON; key_t_press = 1; } else { key_t_cnt ++; } } else { key_t_press = 0; key_t_cnt = 0; } } //-------------------------------------------------------- //переключаем раздаточную коробку в зависимости от статуса void SetTransferBox(uint8_t st,uint8_t lk) { if((st == SEL_2H)||(st == SEL_NO )) { GPIO_WriteHigh(OUT_2H_PORT, OUT_2H_PIN); GPIO_WriteLow (OUT_4L_PORT, OUT_4L_PIN); }else if(st == SEL_4H) { GPIO_WriteLow (OUT_2H_PORT, OUT_2H_PIN); GPIO_WriteLow (OUT_4L_PORT, OUT_4L_PIN); }else if((st == SEL_4L)||(st == SEL_4S )) { if(lk == 1) { GPIO_WriteLow (OUT_2H_PORT, OUT_2H_PIN); GPIO_WriteHigh(OUT_4L_PORT, OUT_4L_PIN); }else { GPIO_WriteLow (OUT_2H_PORT, OUT_2H_PIN); GPIO_WriteLow(OUT_4L_PORT, OUT_4L_PIN); } }else { //2h GPIO_WriteLow (OUT_2H_PORT, OUT_2H_PIN); GPIO_WriteLow (OUT_4L_PORT, OUT_4L_PIN); } } //-------------------------------------------------------- //меняем статус кнопок подогрева сидений void StatusKeyHeat(void) { if(vdc <= (VP_MIN - VP_GIST)) //если напряжение низкое, не греем и статусы не меняем { heat_block = 1; } if(vdc >= (VP_MIN + VP_GIST)) //если напряжение низкое, не греем и статусы не меняем { heat_block = 0; } //--d if(key_d_press == 1) //если нажата кнопка подогрева вод сиденья { if (key_d_change == 0) //и состояние еще не меняли { if(key_d_status == KEY_NO) { key_d_status = KEY_SET; } else { key_d_status = KEY_NO; } WriteStatusEEPROM('d',key_d_status); //запишем новое состояние EEPROM key_d_change = 1; //поменяли кнопку, выставим признак что до отпускания кнопки ничего не делаем } } else { key_d_change = 0; //отпустили кнопку, можно менять состояние снова } //--p if(key_p_press == 1) //если нажата кнопка подогрева пасс сиденья { if(key_p_change == 0) //и состояние еще не меняли { if(key_p_status == KEY_NO) { key_p_status = KEY_SET; } else { key_p_status = KEY_NO; } WriteStatusEEPROM('p',key_p_status); //запишем новое состояние EEPROM key_p_change = 1; //поменяли кнопку, выставим признак что до отпускания кнопки ничего не делаем } } else { key_p_change = 0; //отпустили кнопку, можно менять состояние снова } } //-------------------------------------------------------- //меняем состояние выходов подогрева сидений void SetHeat(void) { if(heat_block == 1) //если подогрев заблокирован { GPIO_WriteLow (D_HEAT_PORT, D_HEAT_PIN); GPIO_WriteLow (P_HEAT_PORT, P_HEAT_PIN); } else { if(key_d_status == KEY_SET) { GPIO_WriteHigh(D_HEAT_PORT, D_HEAT_PIN); } else { GPIO_WriteLow (D_HEAT_PORT, D_HEAT_PIN); } if(key_p_status == KEY_SET) { GPIO_WriteHigh(P_HEAT_PORT, P_HEAT_PIN); } else { GPIO_WriteLow (P_HEAT_PORT, P_HEAT_PIN); } } } //-------------------------------------------------------- //меняем статус выходов переключателя бака void StatusKeyTank(void) { if(key_t_press == 1) //если нажата кнопка смены бака { if(key_t_change == 0) //и состояние еще не меняли { if(key_t_status == KEY_NO) { key_t_status = KEY_SET; } else { key_t_status = KEY_NO; } WriteStatusEEPROM('t',key_t_status); //запишем новое состояние EEPROM key_t_change = 1; //поменяли кнопку, выставим признак что до отпускания кнопки ничего не делаем } } else { key_t_change = 0; //отпустили кнопку, можно менять состояние снова } } //-------------------------------------------------------- //меняем состояние выходов переключателя бака void SetTank(void) { //надо добавить работу с eeprom if(key_t_status == KEY_SET) { GPIO_WriteHigh(TANK_R_PORT, TANK_R_PIN); //B //GPIO_WriteLow(TANK_LED_PORT, TANK_LED_PIN); //R //используем для тестового мигания } else { GPIO_WriteLow(TANK_R_PORT, TANK_R_PIN); //B //GPIO_WriteHigh(TANK_LED_PORT, TANK_LED_PIN); //R //используем для тестового мигания } } //-------------------------------------------------------- //мигание светодиода/тестового выхода в зависимости от режима работы //используем циклический сдвиг раз в 0,2 секунды 12 битного числа //вызывать будем из прерывания системного таймера (раз в миллисекунду) //период мигания равен 12*200мСек=2.4 секунды //длительность импульса кратна 200мСек void LedStatus(uint8_t LedMode) { switch(LedMode) { case 0: LedMask = 0x0555; //мигание быстрое каждые 0.2 секунды (6 раз) break; case 1: LedMask = 0x0001; //1 раз мигнем break; case 2: LedMask = 0x0005; //2 раза мигнем break; case 3: LedMask = 0x0015; //3 раза мигнем break; case 4: LedMask = 0x0055; //4 раза мигнем break; case 5: LedMask = 0x0155; //5 раз мигнем break; case 6: LedMask = 0x0013; //1 раз мигнем длительно 1 коротко break; case 7: LedMask = 0x0053; //1 раз мигнем длительно 2 коротко break; case 8: LedMask = 0x0153; //1 раз мигнем длительно 3 коротко break; default: LedMask = 0x0555; //6 раз мигнем break; } LedDiv++; //досчитали до 0,2 секунды //полный цикл из 16 бит * 0,2 секунды = 4 секунд период мигания if(LedDiv >= 200) { //сдвинем маску в нужную позицию //и выделим бит rolbit = (LedMask & (rolmask << rolcnt)) >> rolcnt; //отправам в функцию светодиода LedT(rolbit); //R //отправам в функцию внешнего светодиода //к следующему биту if( rolcnt < 11 ) { rolcnt ++ ; } else { rolcnt = 0; } //или сбросим если прошли все биты LedDiv = 0; } } //-------------------------------------------------------- //управление светодиодом бака, PA1 void LedT(uint8_t action) //R { if(action == 0) { GPIO_WriteLow(TANK_LED_PORT, TANK_LED_PIN); } else { GPIO_WriteHigh(TANK_LED_PORT, TANK_LED_PIN); } } //-------------------------------------------------------- //прочитать сохраненный в EEPROM статус подогрева сидений или бака //s = 'D' или 'd' - водитель, 'P' или 'p' - пассажир, //'T' или 't' - топливный бак //возвращаем 0 - если выключено, 1 если включено uint8_t ReadStatusEEPROM(char s) { uint8_t stat; uint32_t ByteAddr; uint8_t ByteData = 0; if((s == 'D')||(s == 'd')) { ByteAddr = D_HEAT_EEPROM; } else if((s == 'P')||(s == 'p')) { ByteAddr = P_HEAT_EEPROM; } else if((s == 'T')||(s == 't')) { ByteAddr = T_EEPROM; } else { return 0; //выходим с 0 без чтения } ByteData = FLASH_ReadByte(ByteAddr); if(ByteData == 0xff) { stat = 1; }else { stat = 0; } return stat; } //-------------------------------------------------------- //записать в EEPROM статус подогрева сидений или бака //s = 'D' или 'd' - водитель, 'P' или 'p' - пассажир, //'T' или 't' - топливный бак //st - статус 1 или 0 //возвращаем 1 - если записалось, 0 если ошибка uint8_t WriteStatusEEPROM(char s,uint8_t st) { uint8_t stat = 0; uint32_t ByteAddr; uint8_t ByteData = 0; if((s == 'D')||(s == 'd')) { ByteAddr = D_HEAT_EEPROM; } else if((s == 'P')||(s == 'p')) { ByteAddr = P_HEAT_EEPROM; } else if((s == 'T')||(s == 't')) { ByteAddr = T_EEPROM; } else { return stat; } if(st == 1) { ByteData = 0xff; } else { ByteData = 0x00; } FLASH_Unlock(FLASH_MEMTYPE_DATA); //разблокировать EEPROM FLASH_ProgramByte(ByteAddr, ByteData); //записать байт в EEPROM FLASH_Lock(FLASH_MEMTYPE_DATA); //заблокировать EEPROM stat = 1; return stat; } //-------------------------------------------------------- /* //проверим работу АЦП, все совпадает ! if(vdc < 10000) { workMode = 1; }else if((vdc >= 10000)&&(vdc < 11000)) { workMode = 2; }else if((vdc >= 11000)&&(vdc < 12000)) { workMode = 3; }else if((vdc >= 12000)&&(vdc < 13000)) { workMode = 4; }else if((vdc >= 13000)&&(vdc < 14000)) { workMode = 5; }else if(vdc >= 14000) { workMode = 6; }else { workMode = 0; } */
файл main.c:
Hidden text
#include "stm8s.h" #include "board.h" //-------------------------------------------------------- //переменные uint16_t res_adc; uint8_t flag_out_adc = 0; uint16_t ee_addr = 0; //адрес для eeprom uint8_t ee_data = 0; //данные для eeprom //-------------------------------------------------------- //обработчик прерывания завершения преобразования ADC //22 - это вектор прерывания adc (указано в datasheet) //время ~5uSec INTERRUPT_HANDLER(ADC1_IRQHandler, 22) { res_adc = ADC1_GetConversionValue(); ADC1_ClearITPendingBit(ADC1_IT_EOC); } //-------------------------------------------------------- //обработчик прерывания таймера 4 //23 - это вектор прерывания таймера 4 (указано в datasheet) INTERRUPT_HANDLER(IRQ_Handler_TIM4, 23) { //делаем действия по прерыванию таймера 1mSec SystemMS(); // Сбрасываем флаг прерывания переполнения TIM4_ClearITPendingBit(TIM4_IT_UPDATE); } //-------------------------------------------------------- int main( void ) { //инициализация BoardInit(); //Включаем глобальное разрешение прерывания enableInterrupts(); //основной цикл while(1) { Loop(); } // return 0; //сюда не попадаем }
Это был первый и единственный пока мой опыт с данным микроконтроллером, и этот код послужил как шаблон для последующих изменений функций этого блока. В последующем была чуть изменена схема и код, чуть модернизирована лицевая панель (некоторые кнопки перекрашены под свои пиктограммы):
Автомобиль немного доработали напильником правильными руками, получился хороший вездеход на больших колесах со всеми возможными блокировками и системой контроля давления в шинах. И с тех пор где-то что-то покоряет.
Спасибо, что дочитали. Может это кому-нибудь поможет в творчестве или ремонте, хотел показать как один из вариантов модернизации простых штатных электронных блоков автомобиля, не сильно меняя интерьер.
