Материал: Sb97585

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

3. Создайте объект-очередь:

xQueueHandle q;

В теле функции main(void) между MX_GPIO_Init() и osKernelStart()

напишите:

osThreadDef(PD12_Thread, PE12Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD12_Thread), NULL); osThreadDef(PD13_Thread, PE13Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD13_Thread), NULL); osThreadDef(PD14_Thread, PE14Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD14_Thread), NULL); osThreadDef(PD15_Thread, PE15Thread, osPriorityNormal , 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD15_Thread), NULL); osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(USER_Thread), NULL); osThreadDef(WORK_Thread, WorkThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(WORK_Thread), NULL);

q = xQueueCreate( 4, sizeof( unsigned char ) );

После определения функции MX_GPIO_Init(void) определите функции, прототипы которых создали ранее:

static void StartThread(void const * argument)

{

for(;;)

{

if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)

{

unsigned char toSend;

xQueueSend( q, ( void * ) &toSend, portMAX_DELAY ); //Добавляем в очередь элемент размером 1 байт.

}

osDelay(500);

}

}

static void WorkThread(void const * argument)

{

//Новый поток, выполняющий работу по убиранию элемента из очереди.

for(;;)

{

unsigned char rec; //Создание буфера

xQueueReceive( q, &( rec ), portMAX_DELAY ); //Убираем из очереди один элемент

osDelay(1000);

16

}

}

static void PD12Thread(void const * argument)

{

for(;;)

{

if(uxQueueMessagesWaiting(q)>1)

//Проверка на количество элементов в очереди //Число в правой части неравенства увеличивается на 1 //От первого светодиода к последнему

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_15,GPIO_PIN_SET);

else

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_15,GPIO_PIN_SET); osDelay(100);

}

}

Опишите оставшиеся три функции аналогично первой.

После загрузки проекта на плату протестируйте его, нажав кнопку Reset, а затем удерживайте пользовательскую кнопку в течение нескольких секунд. Светодиоды будут последовательно загораться, пока не будет задействована вся линейка. После отпускания кнопки они начнут в обратном порядке гаснуть, пока не останется гореть один.

Семафоры:

1.В STM32CubeMX создайте проект, поддерживающий использование

FreeRTOS.

2.Запустите проект в Keil uVision5 и откройте файл main.c. Удалите

строки, содержащие автоматически созданную переменную defaultTaskHandle, прототип функции StartDefaultTask, ее реализацию и создание потока osThreadDef в теле функции main(void). Теперь после прототипа функции MX_GPIO_Init(void) нужно создать прототипы следующих функций:

static void StartThread(void const * argument); static void PD12Thread(void const * argument); static void PD13Thread(void const * argument); static void PD14Thread(void const * argument); static void PD15Thread(void const * argument);

3. До описания функции main(void) создайте объект-семафор:

xSemaphoreHandle semaphore;

4. В теле функции main(void) между MX_GPIO_Init() и osKernelStart()

напишите:

17

osThreadDef(PD12_Thread, PD12Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD12_Thread), NULL);

osThreadDef(PD13_Thread, PD13Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD13_Thread), NULL);

osThreadDef(PD14_Thread, PD14Thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD14_Thread), NULL);

osThreadDef(PD15_Thread, PD15Thread, osPriorityNormal , 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(PD15_Thread), NULL);

osThreadDef(USER_Thread, StartThread, osPriorityHigh, 0, configMINIMAL_STACK_SIZE);

osThreadCreate (osThread(USER_Thread), NULL);

5. После определения функции MX_GPIO_Init(void) определите функции, прототипы которых создали ранее:

static void StartThread(void const * argument)

{

semaphore = xSemaphoreCreateCounting( 60000, 0 );

//Инициализация семафора, максимум задач 60000, на данный мо-

мент 0 for(;;)

{

if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)

{

//Читаем, нажата ли пользовательская кнопка xSemaphoreGive(semaphore);

//Выдаем один семафор, то есть даем потокам еще одну задачу

}

osDelay(10); //Периодичность, с которой потокам дается новая задача при нажатой кнопке (10 мс)

}

}

static void PD12Thread(void const * argument)

{

for(;;)

{

xSemaphoreTake( semaphore, portMAX_DELAY);

//Забираем один семафор, то есть сообщаем, что одна задача решена

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12,GPIO_PIN_RESET);

//Выключение диода, подключенного к ножке PD12 osDelay(500);

//Задержка 500 миллисекунд

HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12,GPIO_PIN_SET); //Включение диода, подключенного к ножке PD12

osDelay(100);

//Задержка 100 миллисекунд

}

Составьте самостоятельно оставшиеся три функции.

18

6. Чтобы сборка кода прошла без ошибок, нужно разрешить программе использовать семафоры. Для этого откройте папку с проектом, зайдите в папку Inc, и в файл FreeRTOSConfig.h сразу после строки

#define configQUEUE_REGISTRY_SIZE

8

добавьте

#define configUSE_COUNTING_SEMAPHORES

1

7.Сохраните файл и запустите сборку проекта. Теперь все готово для тестового запуска.

8.После загрузки проекта на плату протестируйте, нажав кнопку Reset,

азатем удерживайте несколько секунд пользовательскую кнопку. Мигание светодиодов будет индикатором того, что функции в потоках выполняют задачи параллельно, а когда все они будут выполнены, мигание прекратится.

Варианты заданий

1.Реализуйте пример «Семафоры».

2.Реализуйте пример «Очереди».

Лабораторная работа 6. ПЛАТФОРМА ПЛИС: ВЕРИФИКАЦИЯ КОДОВ В СРЕДЕ MODELSIM

Цель работы – знакомство с основами языка Verilog и средой разработ-

ки Modelsim.

Синтаксис языка Verilog напоминает синтаксис C-подобных языков, что упрощает его освоение. Основные управляющие конструкции if, while и др. подобны одноименным конструкциям языка C.

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

Разработка устройств на языке Verilog обязательно включает в себя этап моделирования их работы. Одной из популярных сред для этого является

Modelsim разработки Mentor Graphics.

В тестовой оболочке (тестбенче) прописываются два блока: блок initial, который запускается один раз в начале процесса моделирования и служит для формирования начальных значений, и блок always, выполняющийся по положительному фронту тактирования clk.

19

Порядок выполнения работы

1.Создайте проект в среде Modelsim. Запустите Modelsim. Далее выполните последовательность команд меню File→New→Project…, введите название своего проекта и расположение на диске.

Добавьте файлы в проект. Выберите пункт меню Project → Add to Project

→New File… Выберите тип файла Verilog и нажмите ОК.

2.Напишите свой модуль согласно заданию.

3.Напишите тестбенч к созданному модулю.

4.Промоделируйте тестбенч, получите требуемую последовательность данных.

Подразумевается, что созданные в ходе лабораторной работы модули будут впоследствии залиты на отладочную плату DE0-Nano, на которой расположены 4-позиционный DIP-переключатель, линейка из 8 светодиодов и две копки, формирующие управляющий сигнал и сигнал сброса (перезагрузки).

Таблица содержит данные для подключения всех необходимых выводов при выполнении лабораторной работы.

Соответствие выводов ПЛИС и периферийных устройств

Сигнал

Вывод ПЛИС

Генератор 50 МГц

R8

АЦП CS_N

A10

АЦП SCLK

B14

АЦП DOUT

A9

АЦП DIN

B10

LED0

A15

LED1

A13

LED2

B13

LED3

A11

LED4

D1

LED5

F3

LED6

B1

LED7

L3

Кнопка 0

J15

Кнопка 1

E1

DIP-переключатель 0

M1

DIP-переключатель 1

T8

DIP-переключатель 2

B9

DIP-переключатель 3

M15

20

Источник: https://studfile.net/preview/16439025/