大一嵌入式的练习,当初没仔细听不会做

实现编程
1、SysTick 实现秒计时,LCD 实现秒值计数显示;
2、按键 B1 控制 LED 的流水显示方向;
3、8个LED 流水显示,1s 移位 1次;
4、用 LCD 屏显示系统 24C02 存储器系统的启动次数;
5、用ADC1 规则通道实现电位器 R38 电压的模数转换,并分别显示转换编码值和电压值,调节 R38,其 AD 转换值可在调节范围内可变;
6、用TIM1 和 TIM3 分别输出 250Hz 和 300Hz 的矩形波,用 TIM2 测量矩形波的周期和脉冲宽度:
7、矩形脉冲占空比可通过 B2 按钮调节,调节范围 0-90%,调节步长 10%,并用LCD屏显示调节占空比情况。

引用chatgpt部分指引作答:
这是一个关于嵌入式系统开发的任务清单,涉及到硬件和软件编程。根据您提供的信息,我可以为您提供一些基本的代码示例和解释,帮助您实现这些功能。请注意,以下示例是基于假设您使用的是类似于STM32的单片机,并且使用相应的开发环境和库。

1、SysTick 实现秒计时,LCD 实现秒值计数显示:

#include "stm32f4xx.h"
#include "lcd.h"

volatile uint32_t systick_count = 0;

void SysTick_Handler(void) {
    systick_count++;
}

int main(void) {
    SysTick_Config(SystemCoreClock / 1000); // 设置 SysTick 为 1ms 中断一次

    LCD_Init(); // 初始化 LCD

    while (1) {
        uint32_t seconds = systick_count / 1000; // 计算秒数
        LCD_SetCursorPosition(0, 0); // 设置 LCD 光标位置
        LCD_PrintString("Seconds: ");
        LCD_PrintNumber(seconds); // 在 LCD 上显示秒数

        // 其他任务处理
    }
}

2、按键 B1 控制 LED 的流水显示方向:

#include "stm32f4xx.h"

#define LED_GPIO_PORT GPIOA
#define LED_GPIO_PIN GPIO_PIN_0

void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        // 处理按键中断
        // 更改流水显示方向

        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

int main(void) {
    // 配置按键中断

    while (1) {
        // 控制 LED 的流水显示方向

        // 其他任务处理
    }
}

3、8个LED 流水显示,1s 移位 1次:

#include "stm32f4xx.h"

#define LED_GPIO_PORT GPIOB
#define LED_GPIO_PINS GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \
                      GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7

void Delay(uint32_t milliseconds) {
    uint32_t ticks = milliseconds * (SystemCoreClock / 1000);
    while (ticks--) {
    }
}

int main(void) {
    // 配置 LED 引脚为输出模式

    while (1) {
        GPIO_ToggleBits(LED_GPIO_PORT, LED_GPIO_PINS); // 切换 LED 状态
        Delay(1000); // 延时 1s

        // 其他任务处理
    }
}

4、用 LCD 屏显示系统 24C02 存储器系统的启动次数:

#include "stm32f4xx.h"
#include "lcd.h"
#include "24c02.h"

#define EEPROM_ADDRESS 0xA0

void UpdateStartupCount(void) {
    uint8_t count = 0;
    EEPROM_ReadByte(EEPROM_ADDRESS, &count); // 从 24C02 存储器读取启动次数

    count++; // 增加启动次数

    EEPROM_WriteByte(EEPROM_ADDRESS, count); // 写入更新后的启动次数
}

int main(void) {
    LCD_Init(); // 初始化 LCD
    EEPROM_Init(); // 初始化 24C02 存储器

    UpdateStartupCount(); // 更新启动次数

    uint8_t count = 0;
    EEPROM_ReadByte(EEPROM_ADDRESS, &count); // 从 24C02 存储器读取最新的启动次数

    LCD_SetCursorPosition(0, 0);
    LCD_PrintString("Startup count: ");
    LCD_PrintNumber(count); // 在 LCD 上显示启动次数

    while (1) {
        // 其他任务处理
    }
}

5、用 ADC1 规则通道实现电位器 R38 电压的模数转换,并分别显示转换编码值和电压值,调节 R38,其 AD 转换值可在调节范围内可变:

#include "stm32f4xx.h"
#include "lcd.h"

void ADC1_IRQHandler(void) {
    if (ADC_GetITStatus(ADC1, ADC_IT_EOC) != RESET) {
        uint16_t adcValue = ADC_GetConversionValue(ADC1); // 获取转换结果

        // 将 ADC 值转换为电压值
        float voltage = adcValue * (3.3 / 4095.0);

        // 在 LCD 上显示转换结果和电压值
        LCD_SetCursorPosition(0, 0);
        LCD_PrintString("ADC Value: ");
        LCD_PrintNumber(adcValue);

        LCD_SetCursorPosition(1, 0);
        LCD_PrintString("Voltage: ");
        LCD_PrintFloat(voltage, 2);

        ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
    }
}

int main(void) {
    ADC_Init(); // 初始化 ADC
    LCD_Init(); // 初始化 LCD

    ADC_StartConversion(ADC1); // 开始 ADC 转换

    while (1) {
        // 其他任务处理
    }
}

6、用 TIM1 和 TIM3 分别输出 250Hz 和 300Hz 的矩形波,用 TIM2 测量矩形波的周期和脉冲宽度:

#include "stm32f4xx.h"

volatile uint32_t tim2_period = 0;
volatile uint32_t tim2_pulseWidth = 0;

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        static uint32_t startTime = 0;
        static uint32_t endTime = 0;
        static uint8_t captureCount = 0;

        if (captureCount == 0) {
            startTime = TIM_GetCounter(TIM2);
            captureCount = 1;
        } else if (captureCount == 1) {
            endTime = TIM_GetCounter(TIM2);
            captureCount = 0;

            if (endTime > startTime) {
                tim2_period = endTime - startTime;
            } else {
                tim2_period = (0xFFFF - startTime) + endTime;
            }

            tim2_pulseWidth = tim2_period / 2; // 假设脉冲为 50% 占空比
        }

        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

int main(void) {
    TIM1_Init(); // 初始化 TIM1,设置输出频率为 250Hz
    TIM3_Init(); // 初始化 TIM3,设置输出频率为 300Hz
    TIM2_Init(); // 初始化 TIM2,用于测量矩形波的周期和脉冲宽度

    while (1) {
        // 其他任务处理
    }
}

7、矩形脉冲占空比可通过 B2 按钮调节,调节范围 0-90%,调节步长 10%,并用 LCD 屏显示调节占空比情况:

#include "stm32f4xx.h"
#include "lcd.h"

#define BUTTON_GPIO_PORT GPIOA
#define BUTTON_GPIO_PIN GPIO_PIN_1

volatile uint8_t dutyCycle = 0;

void EXTI1_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line1) != RESET) {
        // 处理按键中断
        // 调节矩形脉冲占空比

        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

int main(void) {
    LCD_Init(); // 初始化 LCD

    // 配置按键中断

    while (1) {
        LCD_SetCursorPosition(0, 0);
        LCD_PrintString("Duty Cycle: ");
        LCD_PrintNumber(dutyCycle);
        LCD_PrintString("%");

        // 其他任务处理
    }
}

以上示例代码仅为演示目的,您需要根据您的具体硬件和软件环境进行适当的修改和配置。此外,确保在使用任何外设之前正确初始化和配置它们,以及正确处理中断和其他事件。

通用的参考实现:SysTick 实现秒计时:

#include "stm32f4xx.h"  
  
void HAL_TIM_Base_Init(TIM_HandleTypeDef \*htim)  
{  
    htim->Instance = TIM2;  
    htim->Init.Prescaler = 1000000 - 1;  
    htim->Init.CounterMode = TIM_COUNTERMODE_UP;  
    htim->Init.Period = 60;  
    htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  
    HAL_TIM_Base_Init(htim);  
}  
  
int main(void)  
{  
    HAL_Init();  
    SystemClock_Config();  
    MX_GPIO_Init();  
    MX_TIM2_Init();  
    MX_TIM3_Init();  
    MX_TIM1_Init();  
    MX_LCD_Init();  
    HAL_TIM_Base_Start(&htim2);  
    while (1) {}  
}

按键 B1 控制 LED 的流水显示方向:

#include "stm32f4xx.h"  
  
void MX_GPIO_Init(void)  
{  
    GPIO_InitTypeDef GPIO_InitStruct;  
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  
    GPIO_InitStruct.Pull = GPIO_NOPULL;  
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  
    GPIO_InitStruct.Pin = GPIO_PIN_5;  
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  
}  
  
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t PinMask)  
{  
    HAL_GPIO_WritePin(GPIOA, PinMask, GPIO_PIN_TOGGLE);  
}
#未完待续,如有帮助,恭请采纳

看正点原子的教程,最好买块板子,边学习边练习~

作为一名资深的IT专家,我可以提供以下解决方案:

  1. 实现秒计时可以通过使用SysTick库,该库提供了秒计数器和LCD显示屏。在代码中,需要使用SysTick库中的Gettimeofday函数来获取当前时间,然后将其转换为秒数。
#include <stdio.h>
#include <sys/time.h>

void SysTick_Init() {
    SysTick_Config( SysTick_LOAD_PIN + 1 );
}

int SysTick_Gettimeofday() {
    struct timeval t;
    Gettimeofday(&t);
    return t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
  1. 实现LED流水显示可以通过使用按键B1来控制。在代码中,需要使用GetAsyncKeyState函数来获取按键B1的按下状态,然后将其转换为按键方向。
void GetAsyncKeyState(int key, int *state) {
    if (key == B1) {
        *state = 1;
    }
}
  1. 实现8个LED流水显示可以通过使用LCD库来实现。在代码中,需要使用LCD库中的CreateWindow函数创建一个窗口,然后使用CreatePixel函数获取每个LED的地址,并使用CreateWindow函数将其显示在窗口中。

```c++

include

include

include

int main() { WSADATA wsaData; WSAContext wsaContext;

// 初始化WSAContext
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    printf("WSAStartup failed.\n");
    return 1;
}

// 初始化WSAContext
if (WSAContext(&wsaContext) != 0) {
    printf("WSAContext failed.\n");
    return 1;
}

// 创建LCD窗口
HWND hWnd = CreateWindow(WS_GROUP, "LCD", WS_OVERLAPPEDWINDOW,
    200, 200, 100, 100, hWnd, NULL, NULL, NULL);

// 获取窗口句柄
if (GetWindowLong(hWnd, GWL_HWNDFROMWINDOW) == 0) {
    printf("Failed to get window handle.\n");
    return 1;
}

// 获取LCD窗口的内容
HLCD_Panel hLCDPanel = (HLCD_Panel)GetWindowLong(hWnd, GWL_HWNDFROMWINDOW);
HLCD

好好看例程吧

源于ChatGPT仅供参考:

由于这是一个较为复杂的嵌入式系统编程任务,需要使用硬件和软件相结合的方式来实现。以下是一种可能的实现方案:

```c
#include "stm32f10x.h"
#include "LCD1602.h"

uint32_t sys_counter = 0;   // 记录系统秒数计数器
uint8_t led_dir = 1;        // LED 流水灯方向,1 表示正向,-1 表示反向
uint8_t led_pattern = 0x01; // LED 流水灯的模式

uint16_t adc_value = 0;     // ADC 转换值
float adc_voltage = 0.0f;   // 对应电压值

uint16_t pwm_duty_cycle = 0; // PWM 占空比,范围为 0-9000,步长为 1000

uint16_t tim2_period = 0;   // TIM2 测量的矩形波周期
uint16_t tim2_pulse_width = 0; // TIM2 测量的矩形波脉冲宽度

// SysTick 中断处理函数
void SysTick_Handler(void)
{
    sys_counter++;  // 秒计时计数器加1

    if (sys_counter % 10 == 0) {
        lcd_display_int(2, 0, sys_counter / 10); // 在第二行第一个字符处显示秒值计数
    }

    if (sys_counter % 1000 == 0) {
        // 每隔1秒更新启动次数
        uint8_t start_count = 0;
        eeprom_read(0, &start_count); // 从EEPROM中读取启动次数
        lcd_display_string(1, 0, "Start Count: ");
        lcd_display_int(1, 13, start_count);
        start_count++;
        eeprom_write(0, start_count); // 将启动次数加1写入EEPROM
    }

    if (sys_counter % 100 == 0) {
        // 每隔0.1秒更新LED流水灯状态
        if (led_dir == 1) {
            led_pattern <<= 1;
            if (led_pattern == 0x00) {
                led_pattern = 0x01;
            }
        } else {
            led_pattern >>= 1;
            if (led_pattern == 0x00) {
                led_pattern = 0x80;
            }
        }
        GPIO_Write(GPIOB, led_pattern);
    }
}

// EXTI9_5 中断处理函数,用于控制LED流水灯方向
void EXTI9_5_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line6) != RESET) {
        EXTI_ClearITPendingBit(EXTI_Line6);
        led_dir = -led_dir; // 改变流水灯方向
    }
}

// ADC1 规则通道中断处理函数
void ADC1_2_IRQHandler(void)
{
    if (ADC_GetITStatus(ADC1, ADC_IT_EOC)) {
        adc_value = ADC_GetConversionValue(ADC1);
        adc_voltage = (float)adc_value / 4096 * 3.3f;
        lcd_display_int(3, 0, adc_value);
        lcd_display_string(3, 6, "Voltage: ");
        lcd_display_float(3, 14, adc_voltage, 2);
        ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
    }
}

// TIM2 中断处理函数,用于测量矩形波的周期和脉冲宽度
void TIM2_IRQHandler(void)
{
    static uint16_t last_time = 0;
    static uint8_t measurement_step = 0;

    if (TIM_GetITStatus(TIM2, TIM_IT_Update)) {
        // 定时器溢出中断,重新开始计时
        last_time = 0;
        measurement_step = 0;
        TIM_SetCounter(TIM2, 0);
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }

    if (TIM_GetITStatus(TIM2, TIM_IT_CC1)) {
        // 捕获比较中断,进行周期/脉宽测量
        uint16_t current_time = TIM_GetCapture1(TIM2);

       ...............................................