尝试在 ccs 中使用 FreeRTOS 进行嵌入式编程时遇到困难

问题描述 投票:0回答:1

我尝试在带有键盘和液晶显示屏扩展的 tiva 板上使用 FreeRTOS 在 ccs 中进行一些嵌入式编程(顺便说一句,我不是 C 编程专家)。我为键盘和液晶屏制定了一项任务,它们应该一起工作,将按下的键显示到液晶显示屏上。我能够在 ccs 中编译/调试代码,但是当我尝试按键盘上的按钮时,液晶显示屏上没有显示任何内容。我怀疑他们使用 FreeRTOS 的方式是错误的,或者使其工作的功能是错误的。我希望您查看两个任务(液晶屏和键盘)和 main.c 的代码,看看您是否能找出它不起作用的原因。

任务 1 keypad_task写在 keypad.c 文件中 通过此任务,我尝试扫描并检测键盘上的任何按键,并将按下的按键的值存储到队列中(队列在 main.c 文件中创建)。为了完成此任务,我初始化键盘并创建诸如 scan_keypad、Read_keypad 之类的函数。

任务 2 lcd_task写在 lcd.c 文件中 通过此任务,我试图检测队列中是否有任何内容以及是否将其写入液晶显示器。为了完成这项工作,我做了很多函数,例如 lcd_init(初始化 lcd)、lcd_command、lcd_pulse_enable、delay_us(不确定这个函数是否相关,因为我可以使用 vTaskDelay 代替?)、lcd_write_char 和 lcd_wait_busy

主要.c

/**
 * main.c
 */
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "emp_type.h"
#include "systick_frt.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "keypad.h"
#include "lcd.h"


#define USERTASK_STACK_SIZE configMINIMAL_STACK_SIZE
#define IDLE_PRIO 0
#define LOW_PRIO  1
#define MED_PRIO  2
#define HIGH_PRIO 3
#define QUEUE_SIZE 50


QueueHandle_t LCDQueue;

static void setupHardware(void)

{
 
  init_systick();
  keypad_init();
  lcd_init();

}

int main(void)
{
    setupHardware();
    LCDQueue = xQueueCreate(QUEUE_SIZE, sizeof(char));
    xTaskCreate( keypad_task, "keypad", USERTASK_STACK_SIZE, (void *)LCDQueue, HIGH_PRIO, NULL );
    xTaskCreate(lcd_write_task, "LCD Write Task", USERTASK_STACK_SIZE, (void *)LCDQueue, MED_PRIO, NULL);
    vTaskStartScheduler();
    return 0;
}

键盘.c

#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "FreeRTOS.h"
#include "Task.h"
#include "queue.h"
#include "semphr.h"
#include "emp_type.h"



void keypad_init(void)
{
    INT8S dummy;
    vTaskDelay(10);
    // Enable clock for GPIO Port A and Port E
    SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOA;

    vTaskDelay(10);
    SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOE;

    vTaskDelay(10);
    // Dummy read to ensure the clock is stable
    dummy = SYSCTL_RCGC2_R;

    vTaskDelay(10);
    // Configure PA2-PA4 as inputs for rows
    GPIO_PORTA_DIR_R &= ~0x1C;

    vTaskDelay(10);
    // Configure PE0-PE3 as outputs for columns
    GPIO_PORTE_DIR_R |= 0x0F;

    vTaskDelay(10);
    // Enable digital functionality for PA2-PA4 and PE0-PE3
    GPIO_PORTA_DEN_R |= 0x1C;

    vTaskDelay(10);
    GPIO_PORTE_DEN_R |= 0x0F;

    vTaskDelay(10);
    // Enable pull-up resistors for PA2-PA4 (rows)
    GPIO_PORTA_PUR_R |= 0x1C;
}


char scan_keypad(void)
{
    const char keys[4][3] = {
        {'1', '2', '3'},
        {'4', '5', '6'},
        {'7', '8', '9'},
        {'#', '0', '*'}
    };

    int row;
        for (row = 0; row < 4; row++) {
            // Drive one row (PE0-PE3) low
            GPIO_PORTE_DATA_R = ~(1U << row);
            vTaskDelay(pdMS_TO_TICKS(2));  // Debounce delay
            int col;
            for (col = 0; col < 3; col++) {
                if (!(GPIO_PORTA_DATA_R & (1 << (col + 2)))) { // If button is pressed
                    GPIO_PORTE_DATA_R = 0x0F; // Reset rows to high before exit
                    return keys[row][col];
                }
            }
            // Reset row to high before moving to next
            GPIO_PORTE_DATA_R = 0xFF;
        }
        return '\0'; // No key pressed
    }

char read_keypad(void)
{
    return scan_keypad();
}




void keypad_task(void *pvParameters)
{
    QueueHandle_t LCDQueue = (QueueHandle_t)pvParameters;
    char keyPressed;

    while(1)
    {
        keyPressed = read_keypad(); // Read the keypad input

        if(keyPressed != '\0') // If a key is pressed
        {

            xQueueSend(LCDQueue, &keyPressed, 10); // Send the key to LCD task
        }

        vTaskDelay(50 / portTICK_PERIOD_MS); // Delay to debounce the keypad
    }
}

lcd.c

#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "FreeRTOS.h"
#include "Task.h"
#include "queue.h"
#include "semphr.h"
#include "emp_type.h"
#include "systick_frt.h"



void delay_us(uint32_t us)
{
    // Convert microseconds to milliseconds
    uint32_t ms_delay = (us + 999) / 1000;

    // Use FreeRTOS delay function to wait
    vTaskDelay(ms_delay / portTICK_RATE_MS);
}

void lcd_pulse_enable(void) {
    // Pulse E pin for LCD
    GPIO_PORTD_DATA_R |= 0x08;  // E = 1
    delay_us(1);  // Short delay
    GPIO_PORTD_DATA_R &= ~0x08;  // E = 0
    delay_us(1);  // Short delay
}

void lcd_command(uint8_t command) {
    // Set RS to 0 for command mode
    GPIO_PORTD_DATA_R &= ~0x04;  // RS = 0

    // Send higher nibble first
    GPIO_PORTC_DATA_R = (GPIO_PORTC_DATA_R & 0x0F) | (command & 0xF0);
    lcd_pulse_enable();

    // Send lower nibble
    GPIO_PORTC_DATA_R = (GPIO_PORTC_DATA_R & 0x0F) | ((command & 0x0F) << 4);
    lcd_pulse_enable();

    // Delay after sending command
    delay_us(50);  // You can implement a delay function to wait for LCD to process the command
}

void lcd_init(void) {
    vTaskDelay(10);
    // Enable clock for GPIO Port C and Port D
    SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOC | SYSCTL_RCGC2_GPIOD;

    // Dummy read to ensure the clock is stable
    volatile uint32_t dummy = SYSCTL_RCGC2_R;

    vTaskDelay(10);
    // Configure PC4-PC7 as digital outputs for LCD data
    GPIO_PORTC_DIR_R |= 0xF0;  // PC4-PC7
    vTaskDelay(10);
    GPIO_PORTC_DEN_R |= 0xF0;  // PC4-PC7

    vTaskDelay(10);
    // Configure PD2 and PD3 as digital outputs for LCD control (RS and E)
    GPIO_PORTD_DIR_R |= 0x0C;  // PD2 and PD3
    vTaskDelay(10);
    GPIO_PORTD_DEN_R |= 0x0C;  // PD2 and PD3

    delay_us(2);
    // Initialize LCD (You can modify these initialization commands based on your LCD's requirements)
    lcd_command(0x28);  // 4-bit mode, 2-line display, 5x8 font
    delay_us(2);
    lcd_command(0x06);  // Increment cursor, no display shift
    delay_us(2);
    lcd_command(0x0C);  // Display on, cursor off, blinking off
    delay_us(2);
    lcd_command(0x01);  // Clear display
    delay_us(2);
    lcd_command(0x02);  // Return home
}

void lcd_write_char(uint8_t data) {
    // Set RS to 1 for data mode
    GPIO_PORTD_DATA_R |= 0x04;  // RS = 1

    // Send higher nibble first
    GPIO_PORTC_DATA_R = (GPIO_PORTC_DATA_R & 0x0F) | (data & 0xF0);
    lcd_pulse_enable();

    // Send lower nibble
    GPIO_PORTC_DATA_R = (GPIO_PORTC_DATA_R & 0x0F) | ((data & 0x0F) << 4);
    lcd_pulse_enable();

    // Delay after sending data
    delay_us(10);  // You can implement a delay function to wait for LCD to process the data
}

void lcd_wait_busy(void) {
    // Set RS to 0 for command mode
    GPIO_PORTD_DATA_R &= ~0x04;

    // Configure PC4-PC7 as inputs
    GPIO_PORTC_DIR_R &= ~0xF0;

    // Enable read mode (RW = 1)
    GPIO_PORTD_DATA_R |= 0x02;

    // Wait until BF becomes 0
    while (GPIO_PORTC_DATA_R & 0x80);

    // Restore original settings
    GPIO_PORTD_DATA_R &= ~0x02;
    GPIO_PORTC_DIR_R |= 0xF0;
}

void lcd_write_task(void *pvParameters) {
    QueueHandle_t LCDQueue = (QueueHandle_t)pvParameters;
    char receivedChar;
    lcd_command(0x01);
    while (1) {
        if (xQueueReceive(LCDQueue, &receivedChar, portMAX_DELAY) == pdTRUE) {

            // Write the received character to the LCD
            lcd_wait_busy();
            lcd_write_char((uint8_t)receivedChar);
        }
    }
}

我写了很多代码试图做同样的事情,但我总是得出相同的结论:程序可以编译/调试,但当我按键盘上的键时,液晶显示屏上没有显示任何内容。

最后我想实现这样的功能:当我按下键盘上的一个键时,该键的值会显示在液晶显示屏上,当按下一个新键时,会显示该键的值而不是另一个键。

c freertos texas-instruments
1个回答
0
投票
  1. 在不读键盘的情况下进行测试。只需对一些字符进行排队即可查看是否有效。
  2. 如果有效,请检查您的按键读取功能是否处于死循环中,以及是否正在发送除
    0
  3. 之外的其他内容
  4. 如果不起作用,请检查您的 LCD 写入函数是否没有以死循环结束。 3.1 检查 freeRTOS 配置(中断优先级、堆栈等)
© www.soinside.com 2019 - 2024. All rights reserved.