Нужен совет

Информация из первых уст

Наши авторы

Иван Парфенов

Кирилл Анофриев

Павел Егоров

Анна Киросова

Как восстановить электронную книгу

Есть способ для программного восстановления электронных книг - портативных медиа плееров. Способ работает на книгах фирм Effire, Ritmix, Texet, Teclast и др китайского производства. 
 

Подключение внешнего Wi-Fi адаптера к планшету на андроид 4

#!/system/bin/sh

 

ip link set wlan0 down

iwconfig wlan0 channel auto

iwconfig wlan0 Bit 54Mb/s

iwconfig wlan0 essid 'SSID name'

sleep 10

 

STM32 таймеры для начинающих

В данном примере я расскажу как настроить таймер для STM32F103 установленой на плате Maple Mini в программе Keil с помощью библиотеки SPL. Таймер - это такая штука как в мультфильме - сначала тикает, а потом бьет :). То есть на небольшом участке кристалла нашей микросхемы есть небольшая схема сама по себе, которая может только тикать и "бить". Работать она может сама по себе, независимо от основного процессора, что часто используют для задач повышенной точности. Чтобы таймер заработал - его надо включить, а перед этим желательного его еще и настроить. Настраивается таймер путем записи некоторых значений по некоторым адресам. Последовательность такая:

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

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

Тут мы видим упоминание о неком APB1 - это аббревиатура Advanced Peripherial Bus №1 - к этой шине подключена наша перемычка до таймера, В нашем случае шина APB1 работает на частоте 36MHz - эта цифра настраивается в файле system_stm32f10x.c 

    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
Дальше смотрим в даташите на картинку как что подключено в плане периферии и видим перед нашим Таймером 2 некий прямоугольник, где написано, что если предделитель частоты шины APB1 равен 1, то и множитель частоты для таймера будет 1, в противном случае множитель частоты будет 2! В нашем случае как раз предделель равен 2, т.к. максимальная частота шины APB1 равна 36 МГц, отсюда - частота управляющая таймером будет 36 * 2 = 72 МГц!!!  Запомним это.
Дальше мы хотим включать светодиод на время 1 сек, и выключать его тоже на 1 секунду. Поэтому из 72 МГц надо как-то получить 1 Гц. Делается это при помощи предделителя для счетчика, который настраивается строчкой 
myTmr.TIM_Prescaler =  36000 - 1 ;

Пока отбросим -1 и обратим внимание на 3600 - это делитель к входящей частоте счетчика. Т.е. 72 000 000 Гц / 36 000 = 2 000 Гц - на частоте 2 кГц будет работать наш счетчик, т.е. тикать - его значение будет увеличиваться на 1 каждые 1/2000 секунд. Ньюанс - этот предделитель  в микроконтроллере stm32f103 не может быть больше 65535. Теперь про -1. Единичка получается из выражения в даташите для формулы вычисления частоты счетчика (файл AN2581.pdf):

TIM2 counter clock = TIMxCLK / (Prescaler +1)

Итак, частоту отсчетов счетчика 1/2000 секунд мы получили, осталось сказать счетчику, чтобы тот досчитал до 2000 и выдал бы наружу какой-нибудь сигнал-оповещение. Для этого используем ключевое слово Period:

myTmr.TIM_Period = 2000; 

А чтобы счетчик дал наружу знак о достижении им значения периода - 2000 используют команду

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

и функция-обработчик этого прерывания называется так

void TIM2_IRQHandler()

Остальное все просто, весь рабочий код представлен ниже:

// aim - enable timer and  1000ms ON and 1000 ms OFF
// led on pin PB1
 
#include "RTE_Device.h"                 // Keil::Device:Startup
#include "stm32f10x_gpio.h"             // Keil::Device:StdPeriph Drivers:GPIO
 
 
void gpio_init(void) {
 
GPIO_InitTypeDef gpio;
 
// enable clocking GPIOB block
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
// set output for led pin PB1
 GPIO_StructInit(&gpio);
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    gpio.GPIO_Pin = GPIO_Pin_1;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio);
}
 
void Toggle_Led(void) {
 
if (!GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1)) {
GPIO_SetBits(GPIOB, GPIO_Pin_1); }
else {
GPIO_ResetBits(GPIOB, GPIO_Pin_1); }
 
}
 
void tmr_init(void) {
// TIM2
// according startup file APB1 bus on 36MHz | APB2 on 72 MHz
// Page 90 RefManual stm32f10x says: if APB1 bus prescaler = 1 then TIM CLK mult = 1 else mult = 2
// so in my case APB2 bus presc = 2 then TIM CLK = 2 * 36 MHz = 72 MHz
 
TIM_TimeBaseInitTypeDef myTmr;
 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
 
myTmr.TIM_Prescaler =  36000 - 1 ;
myTmr.TIM_Period = 2000; // for 1 sec pulses
myTmr.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &myTmr);
 
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
 
TIM_Cmd(TIM2, ENABLE);
NVIC_EnableIRQ(TIM2_IRQn);
 
}
 
void TIM2_IRQHandler()
{
 if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
Toggle_Led();
 
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
 
 
 
 
int main()
{
gpio_init();
tmr_init();
 
    while(1) {};
}