Advertisement
Guest User

Untitled

a guest
Jun 19th, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 18.24 KB | None | 0 0
  1. #include "mcu_support_package/inc/stm32f10x.h"
  2.  
  3. #include <app_cfg.h>
  4.  
  5. #include <ucos_ii.h>
  6.  
  7. #include <cpu.h>
  8. #include <lib_def.h>
  9. #include <lib_mem.h>
  10. #include <lib_str.h>
  11. #include "stdbool.h"
  12. #include <bsp.h>
  13.  
  14. #define APP_ASSERT( statement ) do { if(! (statement) ) { __disable_irq(); while(1){ __BKPT(0xAB); if(0) break;} }  } while(0)
  15.  
  16. /***************************************************************************************************
  17.                                  Стеки для тасков
  18.  ***************************************************************************************************/
  19.  
  20. static OS_STK App_TaskStartStack[APP_TASK_START_STACK_SIZE];
  21.  
  22. static OS_STK App_ButtonStack[APP_TASK_BUTTON_STACK_SIZE];
  23.  
  24. static OS_STK App_TaskLed8Stack[APP_TASK_LED8_STACK_SIZE];
  25.  
  26. static OS_STK App_TaskScanKeyboardStack[APP_TASK_KEYBOARD_STACK_SIZE];
  27.  
  28. static OS_STK App_TaskPlaySoundStack[APP_TASK_SOUND_STACK_SIZE];
  29.  
  30. static OS_STK App_TaskSendButtonNumStack[APP_TASK_SEND_BUTTON_NUM_STACK_SIZE];
  31.  
  32. /***************************************************************************************************
  33.                                  Таски - объявления
  34.  ***************************************************************************************************/
  35.  
  36. static void App_TaskStart( void * p_arg );
  37.  
  38. static void App_TaskButton( void * p_arg );// сканирование кнопки PA0
  39.  
  40. static void App_TaskLed8( void * p_arg ); // зажигание светодиода PC8 по нажатию PA0
  41.  
  42. static void App_TaskScanKeyboard( void * p_arg ); // сканирование клавиатуры
  43.  
  44. static void App_TaskPlaySound( void * p_arg ); // играть звук согласно нажатой кнопке
  45.  
  46. static void App_TaskSendButtonNum( void * p_arg ); // отправлять номер нажатой клавиши
  47. //на клавиатуре по USART
  48. OS_EVENT * semaphore;// указатель на семафор
  49. OS_EVENT * queue;// указатель на очередь
  50. #define QUEUE_SIZE 128
  51. static void * queueStorage[ QUEUE_SIZE ]; // массив, в котором будут лежать сообщения
  52.  
  53. int main(void) {
  54.  
  55.     // запрет прерываний и инициализация ОС
  56.     BSP_IntDisAll();
  57.     OSInit();
  58.  
  59.     // создание стартового таска - в нем создаются все остальные
  60.     // почему не создавать всё сразу в main'e?
  61.     // возможно, вы хотите создавать их в зависимости от каких-нибудь условий,
  62.     // для которых уже должна работать ОС
  63.    
  64.     INT8U res = OSTaskCreate(
  65.                     App_TaskStart,     // указатель на таск        
  66.                     NULL,              // параметр вызова (без параметра)
  67.                     &App_TaskStartStack[APP_TASK_START_STACK_SIZE - 1], // указатель на стек
  68.                     APP_TASK_START_PRIO // приоритет
  69.                 );
  70.  
  71.  
  72.    
  73.     APP_ASSERT( res == OS_ERR_NONE );
  74.  
  75.     // запуск многозадачности
  76.     OSStart();
  77.  
  78.     // до сюда выполнение доходить не должно
  79.     return 0;
  80.  
  81. }
  82.  
  83. /***************************************************************************************************
  84.                                  Таски
  85.  ***************************************************************************************************/
  86.  
  87. // стартовый таск
  88. static void App_TaskStart(void * p_arg) {
  89.     // это чтобы убрать warning о неиспользуемом аргументе
  90.     (void)p_arg;
  91.  
  92.     //  Фактически - только настройка RCC - 72 МГц от ФАПЧ  (Initialize BSP functions)
  93.     BSP_Init();
  94.  
  95.     // настройка СисТика
  96.     OS_CPU_SysTickInit();
  97.  
  98.     // таск для сбора статистики - если он нужен                            
  99. #if (OS_TASK_STAT_EN > 0)
  100.     OSStatInit();
  101. #endif
  102.  
  103.     semaphore = OSSemCreate(1); // создание семофора
  104.     queue = OSQCreate( queueStorage, QUEUE_SIZE ); // создание очереди
  105.  
  106.     BSP_IntInit();//для прерываний
  107.  
  108.     // дальше создаются пользовательские таски
  109.    
  110.     INT8U res;
  111.  
  112.     res = OSTaskCreate(
  113.               App_TaskButton, // указатель на функцию      
  114.               NULL,            // параметр - без параметра              
  115.               &App_ButtonStack[APP_TASK_BUTTON_STACK_SIZE - 1], // указатель на массив для стека  
  116.               APP_TASK_BUTTON_PRIO // приоритет
  117.           );
  118.                
  119.     APP_ASSERT( res == OS_ERR_NONE );
  120.  
  121.     res = OSTaskCreate(
  122.               App_TaskLed8,
  123.               NULL,
  124.               &App_TaskLed8Stack[APP_TASK_LED8_STACK_SIZE - 1],
  125.               APP_TASK_LED8_PRIO
  126.           );
  127.                
  128.     APP_ASSERT( res == OS_ERR_NONE );
  129.  
  130.     res = OSTaskCreate(  
  131.               App_TaskScanKeyboard, // указатель на функцию
  132.               NULL, // параметр - без параметра
  133.               &App_TaskScanKeyboardStack[APP_TASK_KEYBOARD_STACK_SIZE - 1], // указатель на массив для стека
  134.               APP_TASK_SCAN_KEYBOARD_PRIO // приоритет
  135.           );
  136.                      
  137.     APP_ASSERT(res == OS_ERR_NONE);
  138.        
  139.     res = OSTaskCreate(
  140.               App_TaskPlaySound, // указатель на функцию
  141.               NULL, // параметр - без параметра
  142.               &App_TaskPlaySoundStack[APP_TASK_SOUND_STACK_SIZE - 1], // указатель на массив для стека
  143.               APP_TASK_PLAY_SOUND_PRIO // приоритет
  144.           );
  145.  
  146.     APP_ASSERT( res == OS_ERR_NONE );
  147.        
  148.     res = OSTaskCreate(
  149.               App_TaskSendButtonNum, // указатель на функцию
  150.               NULL, // параметр - без параметра
  151.               &App_TaskSendButtonNumStack[APP_TASK_SEND_BUTTON_NUM_STACK_SIZE - 1], // указатель на массив для стека
  152.               APP_TASK_SEND_BUTTON_NUM_PRIO // приоритет
  153.           );
  154.  
  155.     APP_ASSERT( res == OS_ERR_NONE );
  156.  
  157.     // этот таск больше не нужен
  158.     OSTaskDel (OS_PRIO_SELF);
  159.                      
  160. }
  161.  
  162. static bool is_button_on = false; // запоминает состояние кнопки PA0
  163.  
  164. // этот таск зажигает светодиод по нажатию кнопки
  165. static void App_TaskLed8( void * p_arg ) {
  166.     // это чтобы убрать warning о неиспользуемом аргументе
  167.     (void)p_arg;
  168.  
  169.     // настройка портов светодиодов и кнопки - делается при первом вызове таска
  170.     // подаем тактирование
  171.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
  172.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
  173.  
  174.     // делаем РС.0 - floating input
  175.     GPIO_InitTypeDef gpioA;
  176.     gpioA.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  177.     gpioA.GPIO_Pin = GPIO_Pin_0;
  178.     gpioA.GPIO_Speed = GPIO_Speed_10MHz;
  179.  
  180.     GPIO_Init( GPIOA, &gpioA );
  181.     // делаем РС.8 - выходом пуш-пулл
  182.     GPIO_InitTypeDef gpioC;
  183.     gpioC.GPIO_Mode = GPIO_Mode_Out_PP;
  184.     gpioC.GPIO_Pin = GPIO_Pin_8;
  185.     gpioC.GPIO_Speed = GPIO_Speed_10MHz;
  186.  
  187.     GPIO_Init( GPIOC, &gpioC );
  188.  
  189.     // таск никогда не должен завершаться через закрывающую скобку
  190.     // поэтому внутри или удаление или бесконечный цикл
  191.     while (1) {
  192.         if (is_button_on == true)
  193.         GPIOC -> ODR |= 1 << 8; // зажечь светодиод при нажатой кнопке
  194.         else GPIOC -> ODR &= ~(1 << 8); // иначе погасить
  195.         // засыпаем на 5 миллисекунд,чтобы поток кнопки захватил управление
  196.         OSTimeDlyHMSM(0, 0, 0, 5);
  197.     }
  198. }
  199.  
  200. // все что делает этот таск - сканирует кнопку
  201. static void App_TaskButton( void * p_arg ) {
  202.     // это чтобы убрать warning о неиспользуемом аргументе
  203.     (void)p_arg;
  204.  
  205.     // настройка портов - делается при первом вызове таска
  206.     // да, в таске для кнопки порты тоже настраиваются - но ведь другой таск может
  207.     // быть и не активен!
  208.  
  209.     // подаем тактирование
  210.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
  211.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
  212.  
  213.     // делаем РС.0 - floating input
  214.     GPIO_InitTypeDef gpioA;
  215.     gpioA.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  216.     gpioA.GPIO_Pin = GPIO_Pin_0;
  217.     gpioA.GPIO_Speed = GPIO_Speed_10MHz;
  218.  
  219.     GPIO_Init( GPIOA, &gpioA );
  220.     // делаем РС.8 - выходом пуш-пулл
  221.     GPIO_InitTypeDef gpioC;
  222.     gpioC.GPIO_Mode = GPIO_Mode_Out_PP;
  223.     gpioC.GPIO_Pin = GPIO_Pin_8;
  224.     gpioC.GPIO_Speed = GPIO_Speed_10MHz;
  225.  
  226.     GPIO_Init(GPIOC, &gpioC);
  227.  
  228.     // таск никогда не должен завершаться через закрывающую скобку
  229.     // поэтому внутри или удаление или бесконечный цикл
  230.     while (1) {
  231.         //если кнопка нажата
  232.         if(((GPIOA->IDR)&1))
  233.         is_button_on = true;
  234.         else is_button_on = false;
  235.         // засыпаем на 5 миллисекунд, чтобы дать время поменять состояние светодиода
  236.         OSTimeDlyHMSM(0, 0, 0, 5);
  237.     }
  238. }
  239.  
  240. static uint8_t button_num = 0;
  241.  
  242. static void App_TaskScanKeyboard(void * p_arg) {
  243.  
  244.     (void) p_arg;
  245.  
  246.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  247.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  248.    
  249.     //строки в режиме input pull up
  250.     GPIO_InitTypeDef DefA;
  251.     DefA.GPIO_Mode = GPIO_Mode_IPU;
  252.     DefA.GPIO_Pin = (GPIO_Pin_1) | (GPIO_Pin_2) | (GPIO_Pin_3) | (GPIO_Pin_4);
  253.     DefA.GPIO_Speed = GPIO_Speed_50MHz;
  254.     GPIO_Init(GPIOA, &DefA); // строки клавиатуры
  255.  
  256.     GPIO_InitTypeDef DefC;
  257.     DefC.GPIO_Mode = GPIO_Mode_Out_OD;
  258.     DefC.GPIO_Pin = (GPIO_Pin_1) | (GPIO_Pin_2) | (GPIO_Pin_3);
  259.     DefC.GPIO_Speed = GPIO_Speed_50MHz;
  260.     GPIO_Init(GPIOC, &DefC); // столбцы клавиатуры
  261.     GPIO_SetBits(GPIOC, (GPIO_Pin_1) | (GPIO_Pin_2) | (GPIO_Pin_3)); // установим столбцы в 1
  262.  
  263.     while (1) {
  264.         INT8U err;
  265.         OSSemPend(semaphore, 0, &err);
  266.         APP_ASSERT(err == OS_ERR_NONE);
  267.         bool is_button_on = false;
  268.         static bool is_prev_button_on = false;
  269.         for (uint8_t cols = 1; cols < 4; cols++) {
  270.             GPIO_ResetBits(GPIOC, 1 << cols); // ставим 0 по очереди по столбцам
  271.             OSTimeDlyHMSM( 0, 0, 0, 4 ); // подождать 4 миллисекунды
  272.             for (uint8_t rows = 1; rows < 5; rows++) { // по очереди проверяем строки
  273.                 if (!(GPIOA->IDR&(1 << rows))) {
  274.                     button_num = (cols-1)+3*(rows-1) + 1; // запоминает номер нажатой кнопки
  275.                     is_button_on = true;
  276.                     break;
  277.                 }
  278.             }
  279. GPIO_SetBits(GPIOC, 1 << cols);
  280.         }
  281. if ((is_button_on == false)&&(is_prev_button_on == false)) button_num = 0;
  282. is_prev_button_on = is_button_on;
  283. OSSemPost(semaphore); // освобождение семафора
  284. OSTimeDlyHMSM( 0, 0, 0, 10 );
  285.     }
  286. }
  287.  
  288. static void TIM3_IRQHandler() {
  289.     TIM_ClearFlag(TIM3, TIM_IT_Update);
  290.     GPIOB-> ODR ^= 1 << 5;
  291. }
  292.  
  293. static void App_TaskPlaySound(void * p_arg) {
  294.  
  295.     (void)p_arg;
  296.  
  297.     static const uint16_t freq[12] = {523, 587, 659, 698, 784, 880, 987, 880, 784, 698, 659, 587}; //частота: ДО, РЕ, МИ, ФА, СОЛЬ, ЛЯ, СИ, ЛЯ, СОЛЬ, ФА, МИ, РЕ
  298.  
  299.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
  300.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  301.  
  302.     TIM_TimeBaseInitTypeDef TIM_InitStruct;
  303.     TIM_TimeBaseStructInit(&TIM_InitStruct);
  304.     TIM_InitStruct.TIM_Period = 100;
  305.     TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Down;
  306.     TIM_TimeBaseInit(TIM3,&TIM_InitStruct);
  307.  
  308.     TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);//настройка прерываний TIM3
  309.     TIM_Cmd(TIM3,ENABLE);//запуск таймера
  310.     BSP_IntVectSet(BSP_INT_ID_TIM3,TIM3_IRQHandler);//разрешаем прерывания
  311.  
  312.     //динамик в режиме push-pull
  313.     GPIO_InitTypeDef DefB; // настройка динамика
  314.     DefB.GPIO_Mode = GPIO_Mode_Out_PP;
  315.     DefB.GPIO_Pin = GPIO_Pin_5;
  316.     DefB.GPIO_Speed = GPIO_Speed_50MHz;
  317.     GPIO_Init(GPIOB, &DefB);
  318.  
  319.     while(1) {
  320.         INT8U err;
  321.         OSSemPend(semaphore, 0, &err);
  322.         APP_ASSERT(err == OS_ERR_NONE);
  323.         //если кнопка нажата           
  324.         if(button_num) {
  325.             TIM_InitStruct.TIM_Prescaler = (72000000 / (200*freq[button_num - 1]))-1;
  326.             TIM_TimeBaseInit(TIM3,&TIM_InitStruct);
  327.             NVIC_EnableIRQ(TIM3_IRQn);//разрешение прерываний таймера TIM3
  328.             //если ничего не нажато
  329.             } else {
  330.             NVIC_DisableIRQ(TIM3_IRQn);
  331.             GPIO_ResetBits(GPIOB,GPIO_Pin_5);
  332.             }
  333.         OSSemPost(semaphore);
  334.         OSTimeDlyHMSM(0, 0, 0, 10);
  335.         }
  336. }
  337.  
  338. volatile char tx_buffer[16];
  339. static int8_t counter = 0;
  340.  
  341. static void USART1_IRQHandler(void) {
  342.     if(USART_GetITStatus(USART1, USART_IT_TC) == SET){ //прерывание по передаче
  343.     USART_SendData(USART1,tx_buffer[counter++]);
  344.     }
  345.     if (counter > 15) {
  346.     counter = 0;
  347.     USART_ITConfig(USART1, USART_IT_TC, DISABLE);
  348.     }
  349. }
  350.  
  351. static void App_TaskSendButtonNum(void * p_arg) {
  352.  
  353.     (void)p_arg;
  354.  
  355.     char value;//значение кнопки в ASCII
  356.  
  357.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  358.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  359.    
  360.     GPIO_InitTypeDef DefB;
  361.     DefB.GPIO_Mode = GPIO_Mode_AF_PP;
  362.     DefB.GPIO_Pin = GPIO_Pin_6; ////РА6(tx)
  363.     DefB.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  364.     DefB.GPIO_Pin = GPIO_Pin_7; //РА7(rx)
  365.     DefB.GPIO_Speed = GPIO_Speed_2MHz;
  366.     GPIO_Init(GPIOB,&DefB);
  367.  
  368.     USART_InitTypeDef USART_struct;
  369.     USART_struct.USART_BaudRate = 57600;
  370.     USART_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  371.     USART_struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  372.     USART_struct.USART_Parity = USART_Parity_No;
  373.     USART_struct.USART_StopBits = USART_StopBits_1;
  374.     USART_struct.USART_WordLength = USART_WordLength_8b;
  375.     USART_Init(USART1,&USART_struct);//настройка режима работы USART
  376.  
  377.     USART_ITConfig(USART1,USART_IT_TC,DISABLE);
  378.     USART_Cmd(USART1, ENABLE);
  379.     BSP_IntVectSet(BSP_INT_ID_USART1,USART1_IRQHandler);//разрешаем прерывания
  380.     NVIC_EnableIRQ(USART1_IRQn);//разрешение прерываний USART1
  381.     while(1) {
  382.         INT8U err;
  383.         OSSemPend( semaphore,0,&err);
  384.         APP_ASSERT(err == OS_ERR_NONE);
  385.         static char prev_15th_symb = 0;
  386.         if(button_num) {
  387.             // перевод кнопки в ASCII
  388.             if(button_num==12) value = 35;// #
  389.             if(button_num==11) value = 48;// 0
  390.             if(button_num==10) value = 42;// *
  391.             else if(button_num<10) value = button_num + 0x30;
  392.             tx_buffer[0] = 'p';
  393.             tx_buffer[1] = 'r';
  394.             tx_buffer[2] = 'e';
  395.             tx_buffer[3] = 's';
  396.             tx_buffer[4] = 's';
  397.             tx_buffer[5] = 'e';
  398.             tx_buffer[6] = 'd';
  399.             tx_buffer[7] = ' ';
  400.             tx_buffer[8] = 'b';
  401.             tx_buffer[9] = 'u';
  402.             tx_buffer[10] = 't';
  403.             tx_buffer[11] = 't';
  404.             tx_buffer[12] = 'o';
  405.             tx_buffer[13] = 'n';
  406.             tx_buffer[14] = ' ';
  407.             tx_buffer[15] = value; // место в сообщении, где должен стоять номер кнопки
  408.             if(prev_15th_symb != tx_buffer[15]) {
  409.                 prev_15th_symb = tx_buffer[15];
  410.                 USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  411.             }
  412.         }
  413.         if(!button_num) {//если ничего не нажато
  414.             tx_buffer[0] = 'n';
  415.             tx_buffer[1] = 'o';
  416.             tx_buffer[2] = 't';
  417.             tx_buffer[3] = 'h';
  418.             tx_buffer[4] = 'i';
  419.             tx_buffer[5] = 'n';
  420.             tx_buffer[6] = 'g';
  421.             tx_buffer[7] = ' ';
  422.             tx_buffer[8] = 'p';
  423.             tx_buffer[9] = 'r';
  424.             tx_buffer[10] = 'e';
  425.             tx_buffer[11] = 's';
  426.             tx_buffer[12] = 's';
  427.             tx_buffer[13] = 'e';
  428.             tx_buffer[14] = 'd';
  429.             tx_buffer[15] = ' ';
  430.             if(prev_15th_symb != tx_buffer[15]) {
  431.                 prev_15th_symb = tx_buffer[15];
  432.                 USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  433.             }
  434.         }
  435.         OSSemPost(semaphore);
  436.         OSTimeDlyHMSM( 0, 0, 0, 15 );
  437.     }
  438. }
  439.  
  440. #ifdef USE_FULL_ASSERT
  441.  
  442. // эта функция вызывается, если assert_param обнаружил ошибку
  443. void assert_failed(uint8_t * file, uint32_t line) {
  444.     /* User can add his own implementation to report the file name and line number,
  445.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  446.  
  447.     (void)file;
  448.     (void)line;
  449.  
  450.     __disable_irq();
  451.     while(1) {
  452.         // это ассемблерная инструкция "отладчик, стой тут"
  453.         // если вы попали сюда, значит вы ошиблись в параметрах вызова функции из SPL.
  454.         // Смотрите в call stack, чтобы найти ее
  455.         __BKPT(0xAB);
  456.     }
  457. }
  458.  
  459. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement