|
Кнопка включения и выключения устройства на STM32F103 |
|
|
|
Dec 21 2013, 20:12
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
Коллеги, посоветуйте, как лучше организовать кнопку включения по типу тех, что в мобильниках - по длительному нажатию.
Мне видится так - устройство при подключении питания стартует и тут же уходит в один из режимов пониженного энергопотребления. Но при этом включает на выход один из пинов, на вход другой пин и ждет, когда на этом пине появится сигнал от первого пина (у меня матричная клавиатура). При этом можно конечно завести таймер, но по мне так лучше инкрементировать некую величину и по достижению ей порога пускать программу дальше - выходить из спящего режима. Как выключать? При нажатии на кнопку начинать отсчет, по достижении временного интервала - делать RESET.
По крайней мере, я так делал несколько лет назад на AVR -работало.
Хочу повторить то же на STM32F103, но сами понимаете, насколько в нем все наворочено, а я новичок в работе с этим камнем. На русском информации по спящим режимам, с примерами кода крайне мало. В связи с чем вопросы:
1. Для описанной задачи - какой режим лучше использовать? Нужно ли что-то отключать на старте, подключенное по умлочанию? 2. Как сделать программный RESET?
P.S. устройство уже собрано и поэтому варианты с использованием RTC (встречал в интернете намеки на его исползование в таких задачах) не подойдет. Вариант с использование пина WKUP тоже не подойдет, у меня на него от батареи через делитель подается напряжение, для анализа его при помощи АЦП.
Сообщение отредактировал Salamander - Dec 21 2013, 20:17
|
|
|
|
|
 |
Ответов
(1 - 12)
|
Dec 21 2013, 21:23
|

Знающий
   
Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467

|
Reset примерно так: Код #define AIRCR_VECTKEY_MASK ((u32)0x05FA0000)
/******************************************************************************* * Function Name : NVIC_GenerateSystemReset * Description : Generates a system reset. * Input : None * Output : None * Return : None *******************************************************************************/ void NVIC_GenerateSystemReset(void) { SCB->AIRCR = AIRCR_VECTKEY_MASK | (u32)0x04; }
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Dec 21 2013, 22:23
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
За RESET спасибо, работает. Насчет RTC - был неправ - оказывается его тоже можно тактировать от внутренней RC цепочки - не знал. В общем, мысль такая - сразу на старте STANBY, раз в 20 мс просыпаться и опрашивать клавиатуру, если нажатие есть, то ждать 1 секунду, после чего еще раз проверять клавиатуру и если клавиша нажата - просыпаться окончательно, если нет - засыпать снова. Кто-нибудь подкинет примерчик пробуждения от будильника, настроенного на внутренний RC генератор? А то я нашел только пример для STM32L152, а там даже имена регистров другие.... Пока, из того, в чем разобрался сделал вот что: вставил в программу это: Код RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); RCC_LSICmd(ENABLE); RTC_ITConfig(RTC_IT_SEC,ENABLE); PWR_EnterSTANDBYMode(); По идее, программа должна зайти в режим ожидания, и через секунду выйти из него. Но не выходит. Как правильно сделать?
Сообщение отредактировал Salamander - Dec 21 2013, 22:01
|
|
|
|
|
Dec 21 2013, 22:40
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 28-06-10
Пользователь №: 58 174

|
В библиотеках stm есть примеры работы с RTC
|
|
|
|
|
Dec 22 2013, 07:19
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
Нашел я пример, как раз того, что мне надо. Код NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
PWR_BackupAccessCmd(ENABLE);
// RTC clock source configuration ---------------------------------------- // Reset Backup Domain BKP_DeInit();
// Enable LSE OSC RCC_LSICmd(ENABLE); // Wait till LSE is ready while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
// Select the RTC Clock Source RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
// Enable the RTC Clock RCC_RTCCLKCmd(ENABLE);
// RTC configuration ----------------------------------------------------- // Wait for RTC APB registers synchronisation RTC_WaitForSynchro();
// Set the RTC time base to 1s RTC_SetPrescaler(32767); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); RTC_SetCounter(0); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); // Set the RTC Alarm after 3s RTC_SetAlarm(3); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_ALR,ENABLE); В обработчике прерывания ничего не писал, просто поставил брейкпоинт. Запускаю - брейкпоинт не срабатывает. Мониторю через отладчик RTC->CNTL - инкрементируется, то есть часы тикают... Куда копать?
Сообщение отредактировал Salamander - Dec 22 2013, 08:24
|
|
|
|
|
Dec 22 2013, 08:20
|
Гуру
     
Группа: Свой
Сообщений: 2 246
Регистрация: 17-03-05
Из: Украина, Киев
Пользователь №: 3 446

|
Есть же специальный пин PA0. При включении питания устройство ждет паузу какую-то и проверяет состояние PA0. Если нажата - выполняет программу, если нет, то засыпает. Просыпается при очередном нажатии, опять ждет и проверяет... ну и т.д. Код /*** настройка режима Standby ***/ RCC->APB1ENR |= (1UL<<28); PWR->CR |= (1UL<<1); PWR->CR &=~(1UL<<0); PWR->CSR|= (1UL<<8); SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; if(PWR->CSR & (1UL<<0)) PWR->CR |= (1UL<<2); Код if(!(GPIOA->IDR & (1UL<<0))) __wfi();
--------------------
Живи днем так, чтобы ночью ты спал спокойно.
|
|
|
|
|
Dec 22 2013, 09:07
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
Цитата Есть же специальный пин PA0. А если так? (см. первый пост) Цитата устройство уже собрано ....Вариант с использование пина WKUP тоже не подойдет, у меня на него от батареи через делитель подается напряжение, для анализа его при помощи АЦП. кроме того, я писал, что клавиатура матричная. так что не пойдет пин А0. Уважаемый smk, вы мне предложили иной вариант работы выключателя в целом. Я же уже выбрал свой вариант, с учетом невозможности использования А0. В настоящий момент - проблема с прерыванием от Alarm. Отношения к пину А0 она не имеет. Прощу помощи именно с Alarm. С уважением. Тихо сам с собою... У меня получилось вот так: основная программа: Код RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); // RTC clock source configuration ---------------------------------------- // Reset Backup Domain BKP_DeInit(); // Enable LSE OSC RCC_LSICmd(ENABLE); // Wait till LSE is ready while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); // Select the RTC Clock Source RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); // Enable the RTC Clock RCC_RTCCLKCmd(ENABLE); // RTC configuration ----------------------------------------------------- // Wait for RTC APB registers synchronisation RTC_WaitForSynchro(); // Set the RTC time base to 1s RTC_SetPrescaler(32767); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); RTC_SetCounter(0); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); // Set the RTC Alarm after 3s RTC_SetAlarm(7); // Wait until last write operation on RTC registers has finished RTC_WaitForLastTask(); //RTC_ITConfig(RTC_IT_SEC, DISABLE); RTC_ITConfig(RTC_IT_ALR,ENABLE);
/* 2 bits for Preemption Priority and 2 bits for Sub Priority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
NVIC_EnableIRQ (RTC_IRQn); NVIC_EnableIRQ(RTCAlarm_IRQn); PWR_EnterSTANDBYMode(); обработчик прерываний Код void RTC_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { RTC_ClearITPendingBit(RTC_IT_ALR); }
} /******************************************************************************* * Function Name : RTCAlarm_IRQHandler * Description : This function handles RTC Alarm interrupt request. * Input : None * Output : None * Return : None *******************************************************************************/
void RTCAlarm_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { RTC_ClearITPendingBit(RTC_IT_ALR); }
} Брейкпоинт в этом случае срабатывает, но почему-то не в обработчике RTCAlarm_IRQHandler, а в RTC_IRQHandler. Естественно, из режима ожидания в этом случае система не выходит.... В чем ошибка?
Сообщение отредактировал Salamander - Dec 22 2013, 09:10
|
|
|
|
|
Dec 22 2013, 09:30
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 28-06-10
Пользователь №: 58 174

|
Вам надо настроить прерывание по внешней линии EXTI17 Код EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); Из спящего режима STANDBY можно выйти только по внешнему прерыванию, поэтому прерывание будильника часов заведено на 17 линию. Еще надо включить тактирование альтернативных функций У вас в прерываниях проверяются одинаковые флаги по будильнику. В обработчике секунды поставьте проверку флага секунды
|
|
|
|
|
Dec 22 2013, 10:14
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
Цитата Вам надо настроить прерывание по внешней линии EXTI17 А производитель пишет, что не надо: http://application-notes.digchip.com/005/5-10387.pdfстр. 13 Цитата To wake up the STM32F10xxx from Standby mode, there is no need to configure the EXTI Line 17. Цитата У вас в прерываниях проверяются одинаковые флаги по будильнику. В обработчике секунды поставьте проверку флага секунды мне не нужна обработка секунды. Я просто констатировал факт что глобальное прерывание срабатывает и флаг RTC_IT_ALR обрабатывается. Цитата Еще надо включить тактирование альтернативных функций Это вы про внешние прерывания? А вот здесь https://my.st.com/public/STe2ecommunities/m...tandby+wake+rtc товарищ пишет, что у него STANDBY тоже не работает и он добавил ради интереса обработку EXTI7 так как в режиме STOP это помогало. В случае с STANDBY - без эффекта. Погодите... вычитал, что в режиме STANDBY теряется содержимое RAM и регистров... А как тогда вообще им пользоваться, если его настраиваешь, настраиваешь - а все сбрасывается.. Повторюсь еще раз - мне надо чтобы при старте контроллер засыпал, просыпался по будильнику раз в секунду, включал одну УЖЕ ОПРЕДЕЛЕННУЮ ножку на выход, другую УЖЕ ОПРЕДЕЛЕННУЮ на вход и проверял на ней уровень. Если уровень высокий, то просыпаемся окончательно, если низкий - засыпаем еще на одну секунду. Как черт возьми это сделать без всяких внешних прерываний?
Сообщение отредактировал Salamander - Dec 22 2013, 09:58
|
|
|
|
|
Dec 22 2013, 10:55
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 28-06-10
Пользователь №: 58 174

|
При пробуждении из режима standby проц тупо сбрасывается, фактически программа стартует сначала. При пробуждении из stop режима проц запускается с того момента в котором он перешел в stop режим. Альтернативные функции включаются командой
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);это альтернативные функции пинов. Я их всегда включаю чтоб потом непонятного гемора не было. Тока что нарыл. Описание standby мода
After waking up from Standby mode, program execution restarts in the same way as after a Reset (boot pins sampling, vector reset is fetched, etc.). The SBF status flag in the Power control/status register (PWR_CSR)indicates that the MCU was in Standby mode. Тебе получается надо при старте программы проверять флаг SBF в регистре PWR_CSR, который покажет тебе что проц был в режиме standby
Тебе надо после пробуждения провести инициализацию проца, затем проверить флаг SBF, затем подать единицу на пин, а с другого пина состояние прочитать, если нет уровня то засыпать на секунду. Я так думаю в прерывание по будильнику из данного режима ты не попадешь. Будильник только разбудит проц и он начнет выполнять прогу с самого начала, там то и надо дергать пин и смотреть за входным пином
|
|
|
|
|
Dec 22 2013, 14:22
|
Местный
  
Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443

|
Заработало! В сухом остатке получилось вот что CODE /* --------------------------------------------------------------------------------*/ // // НАСТРОЙКА ЧАСОВ И ЖДУЩЕГО РЕЖИМА // /* --------------------------------------------------------------------------------*/
void StartRTC_and_STANDBY() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); PWR_WakeUpPinCmd(DISABLE); BKP_DeInit(); RCC_LSICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_SetPrescaler(32767); RTC_WaitForLastTask(); RTC_SetCounter(0); RTC_WaitForLastTask(); RTC_SetAlarm(1); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_ALR,ENABLE); RTC_WaitForLastTask(); NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_EnableIRQ(RTCAlarm_IRQn); PWR_EnterSTANDBYMode(); } int main(void)
{ int ii; double ll; #ifdef USER_DEBUG DBGMCU->CR |= DBGMCU_CR_DBG_STOP; //for debug purpose #endif NVIC_Configuration(); SysTick_Config(SystemCoreClock/1000); delay_init(); SystemInit(); if(PWR_GetFlagStatus(PWR_FLAG_SB)!=RESET) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2ENR_IOPEEN, ENABLE); PWR_ClearFlag(PWR_FLAG_SB);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_SetBits(GPIOE, GPIO_Pin_6); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOE, &GPIO_InitStructure); if (GPIOE->IDR & GPIO_IDR_IDR5) { delay_ms(1000); if (GPIOE->IDR & GPIO_IDR_IDR5) GPIO_ResetBits(GPIOE, GPIO_Pin_6); else StartRTC_and_STANDBY(); } else StartRTC_and_STANDBY(); } else StartRTC_and_STANDBY();
// ДАЛЬШЕ ОСНОВНАЯ ПРОГРАММА Будут какие замечания?
Сообщение отредактировал IgorKossak - Dec 22 2013, 15:51
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Dec 22 2013, 14:49
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 28-06-10
Пользователь №: 58 174

|
Вроде все нормально. Если работает то все отлично)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|