реклама на сайте
подробности

 
 
> Кнопка включения и выключения устройства на STM32F103
Salamander
сообщение Dec 21 2013, 20:12
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 466
Регистрация: 17-11-12
Пользователь №: 74 443



Коллеги, посоветуйте, как лучше организовать кнопку включения по типу тех, что в мобильниках - по длительному нажатию.

Мне видится так - устройство при подключении питания стартует и тут же уходит в один из режимов пониженного энергопотребления. Но при этом включает на выход один из пинов, на вход другой пин и ждет, когда на этом пине появится сигнал от первого пина (у меня матричная клавиатура). При этом можно конечно завести таймер, но по мне так лучше инкрементировать некую величину и по достижению ей порога пускать программу дальше - выходить из спящего режима. Как выключать? При нажатии на кнопку начинать отсчет, по достижении временного интервала - делать RESET.

По крайней мере, я так делал несколько лет назад на AVR -работало.

Хочу повторить то же на STM32F103, но сами понимаете, насколько в нем все наворочено, а я новичок в работе с этим камнем. На русском информации по спящим режимам, с примерами кода крайне мало. В связи с чем вопросы:

1. Для описанной задачи - какой режим лучше использовать? Нужно ли что-то отключать на старте, подключенное по умлочанию?
2. Как сделать программный RESET?

P.S. устройство уже собрано и поэтому варианты с использованием RTC (встречал в интернете намеки на его исползование в таких задачах) не подойдет. Вариант с использование пина WKUP тоже не подойдет, у меня на него от батареи через делитель подается напряжение, для анализа его при помощи АЦП.

Сообщение отредактировал Salamander - Dec 21 2013, 20:17
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 12)
IgorKossak
сообщение Dec 21 2013, 21:14
Сообщение #2


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Посмотрите в сторону готовых решений. Можно найти в сети поискав "Push Button On/Off Controller"
Например LTC2953 или что нибудь другое, более подходящее Вашей задаче.

Или вот ещё.
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Dec 21 2013, 21:23
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 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;
}


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
Salamander
сообщение Dec 21 2013, 22:23
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
nx6310
сообщение Dec 21 2013, 22:40
Сообщение #5


Участник
*

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



В библиотеках stm есть примеры работы с RTC
Go to the top of the page
 
+Quote Post
Salamander
сообщение Dec 22 2013, 07:19
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
smk
сообщение Dec 22 2013, 08:20
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 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();


--------------------
Живи днем так, чтобы ночью ты спал спокойно.
Go to the top of the page
 
+Quote Post
Salamander
сообщение Dec 22 2013, 09:07
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
nx6310
сообщение Dec 22 2013, 09:30
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 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 линию.
Еще надо включить тактирование альтернативных функций

У вас в прерываниях проверяются одинаковые флаги по будильнику. В обработчике секунды поставьте проверку флага секунды
Go to the top of the page
 
+Quote Post
Salamander
сообщение Dec 22 2013, 10:14
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
nx6310
сообщение Dec 22 2013, 10:55
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 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, затем подать единицу на пин, а с другого пина состояние прочитать, если нет уровня то засыпать на секунду.
Я так думаю в прерывание по будильнику из данного режима ты не попадешь. Будильник только разбудит проц и он начнет выполнять прогу с самого начала, там то и надо дергать пин и смотреть за входным пином
Go to the top of the page
 
+Quote Post
Salamander
сообщение Dec 22 2013, 14:22
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 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] - для короткого!!!
Go to the top of the page
 
+Quote Post
nx6310
сообщение Dec 22 2013, 14:49
Сообщение #13


Участник
*

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



Вроде все нормально. Если работает то все отлично)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 13:14
Рейтинг@Mail.ru


Страница сгенерированна за 0.01467 секунд с 7
ELECTRONIX ©2004-2016