Перейти к содержанию

Auratos

Участник
  • Публикаций

    26
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о Auratos

  • Звание
    Участник
  1. Добрый день. Попала ко мне в руки платка с контроллером PIC18F25K22 и проект для нее. Стоит внешний генератор на 4,9152МГц и включен PLL: #pragma config FOSC = HSMP // частота тактового генератора #pragma config PLLCFG = ON #pragma config PRICLKEN = ON #pragma config FCMEN = OFF ... Стоит задача оценить, с какой максимальной частотой можно с помощью этого контроллера передавать через RS-485 на компьютер данные (число float, 4 байта), если не брать в расчет задержки на выполнение сторонних алгоритмов (чистый проект), а сконцентрироваться только на обмене по сети. В данный момент проект сконфигурирован на скорость 9600 бод: void usart_init(void) { UINT_32 tmp; TRISCbits.TRISC6 = 0; // установить 0 вывод порта А как выход ANSELCbits.ANSC6 = 1; tmp = 4915200; // вычисление частоты USART по формуле SPBRG = Fosc/16 - 1 tmp /= 4; tmp /= 9600; tmp--; //не Fosc, а 4xFosc SPBRG1 = (BYTE)tmp; // устанавливаем частоту USART1 TXSTA1bits.SYNC = 0;// установка асинхронного режима TXSTA1bits.BRGH = 1; RCSTA1bits.SPEN = 1;// включить модуль USART1 PIR1bits.RCIF = 0; // очистить буфер приемника PIE1bits.RCIE = 1; // прерывание от приемника USART разрешено PIE1bits.TXIE = 0; // прерывание от передатчика USART запрещено IPR1bits.RCIP = 0; // приоритет прерывания от приемника USART - низкий IPR1bits.TXIP = 0; // приоритет прерывания от передатчика USART - низкий TXSTA1bits.TX9 = 0; // 8 разрядная передача RCSTA1bits.RX9 = 0; // 8 бит принятых данных RCSTA1bits.CREN = 1; // разрешить прием TXSTA1bits.TXEN = 1; // разрешить передачу } Нашел в даташите табличку со скоростями, настройками USART. Если вкратце, то на скорость влияют только 3 регистра: SYNC, BRGH и BRG16. В данном проект они сконфигурированы так: SYNC = 0, BRGH = 1, BRG16 = 0. Формально можно выставить максимальную скорость 115200 бод. Исходя из формулы V_bit = V_uart * d / (d + 1 + s + p) где: V_uart — скорость UART (например: 9600, 115200), бод; d — количество бит данных; s — количество стоповых бит; p — количество бит четности, p = 1 если бит четности присутствует, или p = 0 если бит четности отсутствует; единица в знаменателе отражает наличие стартового бита. Т.е. 1 бит на скорости 115200 бод будет передаваться в идеале со скоростью: 115200 * 8 / (8 + 1 +1 + 0) = 92160 бит/с = 11520 байт/с = 2880 float/c = 2,88 кГц. Подскажите, пожалуйста, способен ли данный контроллер работать на 115200? На сколько упадет частота с учетом задержек при передаче между байтами/внутри байта? Каким-нибудь ПО можно оценить скорость передачи?
  2. STM32F107RCT6 Настройки таймера

    Добрый день. У меня контроллер STM32F107RCT6. Настраиваю таймеры TIM1 и TIM2 для генерации частоты на выводах. TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef TIM_OCConfig; void TIM1_Init(uint16_t presc, uint16_t period, uint16_t repCnt) { TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef TIM_OCConfig; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // тактирование таймера // выход TIM1_CH1 (F1) GPIO_mInit(GPIO_Speed_50MHz, GPIO_Mode_AF_PP, GPIOA, GPIO_Pin_8); TIM_TimeBaseStructInit(&timer); // заполнение поля структуры дефолтными значениями timer.TIM_Prescaler = presc; // предделитель timer.TIM_Period = period; // период timer.TIM_RepetitionCounter = repCnt; // счетчик повторений TIM_TimeBaseInit(TIM1, &timer); // инициализация TIM1 TIM_ARRPreloadConfig(TIM1, ENABLE); TIM1->BDTR |= TIM_BDTR_MOE; // включение выхода таймера TIM1 TIM_OCStructInit(&TIM_OCConfig); TIM_OCConfig.TIM_OCMode = TIM_OCMode_Toggle; TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable; TIM_OC1Init(TIM1, &TIM_OCConfig); // включение канал1 таймера TIM1 TIM_Cmd(TIM1, ENABLE); // включение таймера TIM1_CH1(F1) } TIM1_Init(7, 17999, 1); TIM2_Init(7, 17999); Шина APB1 работает на частоте 36МГц, а APB2 - на 72МГц. Причем частоту фиксирую непосредственно перед инициализацией таймеров. Из даташита на таймеры на STM32 я вижу формулу, по ней произвожу расчет выходной частоты Взять, например, таймер TIM1: 72000000 / ((7 + 1) * (17999 + 1) * (0 + 1)) = 500Гц. Но фактически на осциллографе вижу частоту 249,9Гц, то есть делиться ровно в 2 раза. Пробовал на разных частотах - результат тот же. Подскажите, пожалуйста, в чем может быть косяк? И еще одна непонятная ситуация - изменения значения RepetitionCounter не влияет на выходную частоту. Пробовал и 1, и 2, и 170 - результат один. Как работает этот RepetitionCounter?
  3. STM32F107RCT6 Time base generator

    Спасибо большое. Помогло :biggrin:
  4. STM32F107RCT6 Time base generator

    Добрый день. У меня контроллер STM32F107RCT6. Хочу сделать тактовый генератор на таймере TIM1 (на 1-й канал выдавать частоту). Вроде все инициализировал (таймер, ножку PA8 для Ch1), а на ножке все равно глухо. Частота кварца 72MГц. Т.е. при текущей настройке на выходе должна быть частота 100Гц. Подскажите, пожалуйста, в чем может быть загвоздка? С контроллером серии STM32L100 у меня получалось, там просто некоторые структуры библиотечные выглядят немного иначе. А вот с этим контроллером никак int main( void) { TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef TIM_OCConfig; SystemCoreClockUpdate (); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2ENR_AFIOEN, ENABLE); GPIO_mInit(GPIO_Speed_10MHz, GPIO_Mode_AF_PP, GPIOA, GPIO_Pin_8); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); TIM_TimeBaseStructInit(&timer); timer.TIM_Prescaler = 11000; timer.TIM_Period = 65; TIM_TimeBaseInit(TIM1, &timer); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_OCStructInit(&TIM_OCConfig); TIM_OCConfig.TIM_OCMode = TIM_OCMode_Toggle; TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable; TIM_OC1Init(TIM1, &TIM_OCConfig); TIM_Cmd(TIM1, ENABLE); // Включение таймера TIM1_CH1(F1) while(1) { wdt_reset(); // сброс WDT } }
  5. Мне уже на другом форуме рассказали, что "в одном флаконе" такого нет, нужно будет делать самому. Защиту по току еще можно найти в драйверах, а вот контроля положения - нет :rolleyes: Поэтому сейчас мне интересно узнать хотя бы названия российских производителей/поставщиков с более-менее крупной линейкой контроллеров/драйверов под разные нужды
  6. Подскажите, пожалуйста, хотя бы названия нескольких производителей, желательно, российских, кто занимается производством или поставками драйверов Скажите, пожалуйста, а чем примечателен именно этот контроллер?
  7. Добрый день. Товарищи, подскажите, пожалуйста, недорогие модели (до 300-400 рублей) контроллеров шаговых двигателей или даже готовые драйвера шаговых двигателей (цена до 1000 рублей), кто уже интересовался, сталкивался или знает, где можно поискать. Параметры: вых. напряжение 5В, вых. ток до 2.5А. Желательно наличие функций считывание текущего положения двигателя, т.е. некий аналог датчика положения, чтобы после подачи питания можно было определить количество уже сделанных шагов. И защита от перегрузок в крайних положениях, когда поступает команда "Сделай шаг", а двигатель уже в крайнем положении. Желательно контроллеры более-менее популярных, проверенных и доступных производителей с большой линейкой аналогичной продукции
  8. Принцип работы RTC в STM32F107

    Цитата(Baser @ Feb 28 2018, 16:04) 2038 год будет уже всего-то через 20 лет. А время бежит быстро. Вот сделаете вы какой-нибудь удачный прибор, и будут люди применять его 20 лет и хвалить. А тут раз - и из-за ошибки времени облом. Зачем сознательно закладывать ошибку, если ее можно легко избежать Все верно. Создаем вычислительное устройство, настал момент его сертифицировать, где мы гарантируем 15 лет бесперебойной работы, поэтому уже через 4 года мы не сможем гарантировать указанный срок службы, т.к. 2022 + 15 = 2037 год
  9. Принцип работы RTC в STM32F107

    Цитата(Baser @ Feb 28 2018, 12:25) Это библиотечная фунция, входящая в Си. В ней применяется UNIX-время (Unix Epoch). Отсчет начинается от 1 января 1970 года. 2036-м годом ограничено, потому что в 2038 UNIX-время достигнет 2х31 и может неверно интерпретироваться как отрицательное. Почитайте по ссылке. Вы можете сдвигать время как угодно, но при этом нужно будет применять свои функции или сдвигать стандартные. Я применяю время с 1 января 2000 года. Переписал функции и использую такой свой Timestamp. И вы также используете библиотечные функции localtime и mktime? А не могли бы вы, пожалуйста, привести пример своих функций для работы со временем?
  10. Принцип работы RTC в STM32F107

    Цитата(viakon @ Feb 28 2018, 10:28) Откуда, зададите оттуда и будет. Главное правильно преобразовать при синхронизации часов. Можно, пожалуйста, поподробнее? Просто я пользуюсь библиотечной функцией при установке времени и даты Кодvoid Set_Time(struct tm *t) {   uint32_t CounterValue = (uint32_t)mktime(t);   save_Time(CounterValue; } void save_Time(uint32_t tmr) {   RTC_WaitForLastTask();   RTC_SetCounter(tmr);   RTC_WaitForLastTask(); } Так вот, функция mktime не воспринимает дату позже февраля 2036 года (найдено опытным путем вплоть до минуты и секунды), т.к. при инкрементации новой секунды происходит переполнение 32-битного CounterValue. Или я неправильно Вас понял? Как выставить дату больше указанной?
  11. Принцип работы RTC в STM32F107

    Добрый день. Имеется на руках контроллер серии STM32F107xx. Пользуюсь активно таймером реального времени. И вот, собственно, возник вопрос: а какой у этого таймера диапазон измерения времени? Т.к. там 32-битный секундный счетчик, то максимум он сможет отсчитать ~136 лет. Отсчет начинается, как я понял, с 1900 года, т.е. до 2036 года. А что будет после его переполнения, т.е. после 2036 года? Можно ли самому подвинуть точку отсчета? Или там совсем все устроено по-другому? Объясните, пожалуйста
  12. STM32F107. Модуль USB не передает данные

    Добрый день. Не нашел отдельной ветки для STM-контроллеров, поэтому пишу сюда. Имеется контроллер STM32F107RCT6. Задействовал у него модуль USB и взял с сайта ST последнюю версию библиотеки и драйвера USB (STM32_USB_OTG_Driver v2.2.0). На плате также имеется GSM-модуль фирмы SIMCOM. Спаяли две платы с данными контроллерами. Одна работает, вторая "болеет". Проблема в том, что если не вставлена SIM-карта, то USB модуль работает отлично. Но со вставленной SIM-картой и после прохождения этапа регистрации в сети перестает работать обмен данными через USB: принимать данные - принимает, но обратно не передает. Попробовали сначала перепаять контроллер и просмотреть линии, ведущие к USB - не помогло. Стал теперь копаться в драйвере. В рабочей версии платы при попытке передать данные в USB порт в функции USBD_OTG_ISR_Handler дважды генерируется некое прерывание, которое драйвер относит к группе inepint Кодuint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) {   USB_OTG_GINTSTS_TypeDef  gintr_status;   uint32_t retval = 0;      if (USB_OTG_IsDeviceMode(pdev)) /* ensure that we are in device mode */   {     gintr_status.d32 = USB_OTG_ReadCoreItr(pdev);          ...          if (gintr_status.b.inepint)     {       retval |= DCD_HandleInEP_ISR(pdev);     }         ...     }   return retval; } При обнаружении данного прерывания вызывается функция DCD_HandleInEP_ISR Кодstatic uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev) {   USB_OTG_DIEPINTn_TypeDef  diepint;      uint32_t ep_intr;   uint32_t epnum = 0;   uint32_t fifoemptymsk;   diepint.d32 = 0;   ep_intr = USB_OTG_ReadDevAllInEPItr(pdev);      while ( ep_intr )   {     if ((ep_intr & 0x1) == 0x01) /* In ITR */     {       diepint.d32 = DCD_ReadDevInEP(pdev , epnum); /* Get In ITR status */       if ( diepint.b.xfercompl )       {         fifoemptymsk = 0x1 << epnum;         USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0);         CLEAR_IN_EP_INTR(epnum, xfercompl);         /* TX COMPLETE */         USBD_DCD_INT_fops->DataInStage(pdev , epnum);                  if (pdev->cfg.dma_enable == 1)         {           if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_IN))           {             /* prepare to rx more setup packets */             USB_OTG_EP0_OutStart(pdev);           }         }                 }       if ( diepint.b.timeout )       {         CLEAR_IN_EP_INTR(epnum, timeout);       }       if (diepint.b.intktxfemp)       {         CLEAR_IN_EP_INTR(epnum, intktxfemp);       }       if (diepint.b.inepnakeff)       {         CLEAR_IN_EP_INTR(epnum, inepnakeff);       }       if ( diepint.b.epdisabled )       {         CLEAR_IN_EP_INTR(epnum, epdisabled);       }             if (diepint.b.emptyintr)       {         DCD_WriteEmptyTxFifo(pdev , epnum);       }     }     epnum++;     ep_intr >>= 1;   }      return 1; } За эти два прерывания, про которые я упомянул, поочередно взводятся два флага: diepint.b.emptyintr и diepint.b.xfercompl. Возведение diepint.b.xfercompl как раз и сигнализирует о том, что данные пошли на отправку. Но в нерабочей плате взводится только diepint.b.emptyintr, и статус USB так и остается как "занят", но при этом данные не передались. Стал копаться глубже и зашел в тупик. Подскажите, пожалуйста, что можно посмотреть еще? Линии, регистры? Любая подсказка
  13. Добрый день. В данный момент у меня на руках плата с контроллером PIC18F25K22 и проект от предыдущего сотрудника. Если очень рассказать очень сжато суть проекта, то есть первичный преобразователь расхода, который состоит из магнито-механического клапана, поршня и катушки индуктивности, обеспечивающей индикацию перемещения поршня в клапане и частичное управление поршнем. При открытии клапана на катушке формируется положительный потенциал, что может быть установлено с помощью компаратора, настроенного на верхний предел (ножка RA4, она же C1OUT). При закрытии клапана на катушке формируется отрицательный потенциал, что приводит к срабатыванию компаратора, если он настроен на нижний предел. Так вот, весь механизм фиксации открытия/закрытия клапана построен на 7 ключевых точках, в которых мониторятся определенные состояния и производятся определенныедействия. Компаратор настроен так: КодTRISAbits.RA4 = 0;      // установить порт RА4 на выход (выход компаратора) PORTAbits.RA4 = 0; CM1CON0bits.C1POL = 0;      // логика на C1OUT не инвертирована CM1CON0bits.C1SP = 0;       // компаратор работает в режиме малой мощности и низкой скорости CM1CON0bits.C1R = 0;         CM1CON0bits.C1CH = 1;   // выставить канал компаратора на верхний предел IPR2bits.C1IP = 1;          // приоритет прерываний от компаратора C1 высокий И обработчик его прерывания: Кодvoid high_isr() {      if (PIR2bits.C1IF)               // прерывание от компаратора     {             if ((PIE2bits.C1IE) && (T3CONbits.TMR3ON == 0)) // если прерывания от компаратора разрешены и таймер TMR3 свободен                 FFComparator1Interrupt();           // войти в обработчик прерываний компаратора             CM1CON0bits.C1OUT = 0;                     // выставить 0 на выходе компаратора             PIR2bits.C1IF = 0;           // сбросить флаг прерывания     } } Все начинается с состояния PPR_CLOSE: Кодvoid FFComparator1Interrupt() {     switch(PPR.State)     {         case PPR_CLOSE:                     DelayInterrupt = 0; //исключаем пересечения                     if (CM1CON0bits.C1CH == 1)              // если компаратор переключен на верхний порог (т.е. фиксируем движение клапана)                     {                         PPR.State = PPR_START_OPEN;  // изменить состояния клапана на "Начал открываться"                         PIE2bits.C1IE = 0;                      // отключить прерывания от компаратора                         PORTAbits.RA4 = 1;                      // поднять уровень сигнала на линии TAU                         CM1CON0bits.C1OE = 0;                   // отключить выход компаратора (не реагировать на изменения на выходе)                         timer3Delay(2);                         // установить задержку в 2мс                         DelayInterrupt = 1;          // выставить флаг для обработчика прерываний таймера TMR3                     }                     else                     {                         CM1CON0bits.C1CH = 1;              // переключить компаратор на верхний порог                     }                     break;     }     return; } В следующем же состоянии PPR_START_OPEN: Кодvoid FFTimerEvent() {     switch(PPR.State)     {         case PPR_START_OPEN:                     if (CM1CON0bits.C1CH == 1)              // если компаратор переключен на верхний порог                     {                         if (CM1CON0bits.C1OUT == 1)                // если клапан действительно открывается                         {                             timer3Delay(40);                    // установить задержку в 40мс для исключения дребезга                             DelayInterrupt = 1;      // выставить флаг для обработчика прерываний таймера TMR3                             PPR.State = PPR_PRE_OPEN;// изменить состояния клапана на "Почти открылся"                             StateChanged = 1;        // выставить флаг о смене состояния клапана                         }                         else                                    // иначе это был дребезг                         {                             PPR.State = PPR_CLOSE;                             CM1CON0bits.C1OE = 1;               // подключить выход компаратора                             PIR2bits.C1IF = 0;       // сбросить флаг прерывания компаратора                             PIE2bits.C1IE = 1;                  // включить прерывания от компаратора                         }                     }                     else                     {                         CM1CON0bits.C1CH = 1;               // переключить компаратор на верхний порог                         timer3Delay(1);                         // установить задержку в 1мс                         DelayInterrupt = 1;          // выставить флаг для обработчика прерываний таймера TMR3                     }                     break;     } } При попытке разобраться возникли спорные моменты: подскажите, пожалуйста 1. зачем по окончании обработки прерывания компаратора выставляется CM1CON0bits.C1OUT = 0 ? 2. зачем в след. за первым состоянием мониторится CM1CON0bits.C1OUT == 1, когда только что был CM1CON0bits.C1OUT = 0 ? Что мы просто мониторим в данном случае, и что сейчас на выходе компаратора реально? 3. действие PORTAbits.RA4 = 1 в первом состоянии не идентично CM1CON0bits.C1OUT = 1? Просто по даташиту Pin #6 = RA4 (C1OUT, SRQ, CCP5, T0CKI) Связаны ли эти два действия вообще друг с другом и как? И если кому то интересно, то вот изображение самого сигнала (измеряемый промежуток находится между вертикальными пунктирными линиями): [attachment=108231:1.jpg]
  14. C18 Ограничения sprintf

    megajohn, большое спасибо за помощь. До этого пробовал %u, %ul, но не работало
  15. C18 Ограничения sprintf

    Добрый день. У меня есть число типа float. Необходимо его записать в массив, дополнив целую и дробную части до определенного размера нулями. С целой частью проблем нет, дробную пока не получилось дополнить нулями. Но проблема в другом: sprintf отказывается принимать числа больше int. Подскажите, пожалуйста, как можно ли как-то обойти это ограничение? Может быть в настройках компилятора что-то включить? Среда разработки - MPLab X IDE. Вот пример кода, где я использую sprintf Кодvoid main(void) {     float minSet1 = 0.5;     unsigned char Setting[11] = "          ";     NumbConverter(Setting, minSet1, 36); } void NumbConverter (void* destination, float numb, unsigned char numbDecimal) {     unsigned char* array = (unsigned char*)destination;     unsigned int whole;     unsigned long decimal;     whole = numb;                                           // целая часть     switch (numbDecimal)     {         case 36:             decimal = (numb - whole) * 1000000;             // дробная часть             sprintf((char*)array, (const far rom char*)"%03d.%06u", whole, decimal);             break;         case 43:             decimal = (numb - whole) * 1000;                // дробная часть             sprintf((char*)array, (const far rom char*)"%04d.%03u", whole, decimal);             break;         case 46:             decimal = (numb - whole) * 1000000;             // дробная часть             sprintf((char*)array, (const far rom char*)"%04d.%06u", whole, decimal);             break;     } } На выходе я получаю массив Setting с содержимым "000.000007" вместо "000.500000". Не знаю, как быть