一、已知一数组如下,要求编写实现如下要求的函数。
int numlist[] = {123, 456, 234, 345, 12, 2, -2,’a’,’b’};
1. 统计以上组数中的奇数的个数,并写出结果。
2. 用一个函数求出数组中最大数和最小数,并返回或取出。
3. 按从小到大的顺序重新排列,并保存回numlist数组中。
- 计算奇数的个数。
#include<stdio.h>
int countOddNumbers(int numlist[], int size) {
int count = 0;
for (int i = 0; i < size; i++) {
int num = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];
if (num % 2 != 0) {
count++;
}
}
return count;
}
int main()
{
int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };
int size = sizeof(numlist) / sizeof(numlist[0]);
int count;
count = countOddNumbers(numlist,size);
printf("奇数个数为%d\n", count);
return 0;
};
2、计算最大值最小值
#include<stdio.h>
void findMinMax(int numlist[], int size,int *max,int *min) {
int Max = *max;
int Min = *min;
for (int i = 0; i < size; i++)
{
int num = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];
if (num > *max)
*max = num;
if (num < *min)
*min = num;
}
}
int main()
{
int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };
int size = sizeof(numlist) / sizeof(numlist[0]);
int min, max;
findMinMax(numlist, size, &max, &min);
printf("最大值:%d\n", max);
printf("最小值:%d\n", min);
return 0;
};
3、从小到大排列
#include<stdio.h>
void sortArray(int numlist[], int size) {
int temp;
for (int i = 0; i < size - 1; i++)
{
for (int j = i+1; j < size; j++)
{
int num1 = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];
int num2 = (numlist[j] >= 'a' && numlist[j] <= 'z') ? numlist[j] - 'a' + 97 : numlist[j];
if (num1 > num2)
{
temp = numlist[i];
numlist[i] = numlist[j];
numlist[j] = temp;
}
}
}
}
int main()
{
int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };
int size = sizeof(numlist) / sizeof(numlist[0]);
sortArray(numlist, size);
printf("排序后的数组: ");
for (int i = 0; i < size; i++) {
if (numlist[i] >= 97 && numlist[i] <= 122) {
printf("%c ", numlist[i] - 97 + 'a');
}
else {
printf("%d ", numlist[i]);
}
}
printf("\n");
return 0;
};
二、有一单片机系统,其中PTA0脚连接一按键开关KEY1,PTA1脚连接LED指示灯。如图。请编写函数实现如下功能。
注:PTA0和PTA1可以使用自己熟悉的芯片IO端口替换。
1、短按开关KEY1,要求LED灯点亮,再次短按开关KEY1,要求LED灯关闭。
2、长按开关KEY1,要求控制LED灯闪烁(亮1S,灭1S),闪烁状态下,短按开关KEY1,LED灯关闭。
3、在同一个函数中实现1,2两个问题的功能。
4、请用时序图表述以上功能。
#include "stm32f1xx_hal.h"
// 定义LED和KEY1的GPIO引脚
#define LED_PIN GPIO_PIN_1
#define LED_GPIO_PORT GPIOA
#define KEY1_PIN GPIO_PIN_0
#define KEY1_GPIO_PORT GPIOA
// 按键去抖时间和长按
#define DEBOUNCE_DELAY 50 // ms
#define LONG_PRESS_THRESHOLD 1000 // ms
// 状态变量
volatile uint8_t led_state = 0; // 0: LED熄灭, 1: LED点亮
volatile uint8_t is_long_press = 0; // 0: 非长按, 1: 长按中
volatile uint32_t press_start_time = 0; // 按键按下开始时间
// 定时器句柄,用于测量时间
TIM_HandleTypeDef htim2;
// 按键中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
static uint8_t last_state = GPIO_PIN_RESET; // 上一次按键状态
uint32_t current_time = HAL_GetTick(); // 获取当前时间
if (GPIO_Pin == KEY1_PIN) {
if (HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_PIN) == GPIO_PIN_SET) { // 按键按下
if (last_state == GPIO_PIN_RESET) { // 边缘检测,从释放到按下
press_start_time = current_time; // 记录按键按下时间
}
} else { // 按键释放
uint32_t press_duration = current_time - press_start_time; // 计算按键按下持续时间
if (press_duration < DEBOUNCE_DELAY) {
return;
}
if (press_duration < LONG_PRESS_THRESHOLD) {
// 短按
led_state = !led_state; // 切换LED状态
HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);
is_long_press = 0; // 重置长按状态
} else {
// 长按
is_long_press = 1;
// 启动闪烁
HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
last_state = GPIO_PIN_SET; // 更新上一次状态为按下(为了下一次检测释放)
// 重置按键按下开始时间,为下一次按键操作做准备
press_start_time = 0;
}
}
}
// 定时器中断服务函数(用于闪烁控制)
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 定时器回调函数(用于闪烁控制)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim2) {
if (is_long_press) {
led_state = !led_state; // 切换LED状态以实现闪烁
HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);
if (HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_PIN) == GPIO_PIN_RESET) {
led_state = 0;
HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, GPIO_PIN_RESET);
is_long_press = 0; }
}
}
}
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start_IT(&htim2);
while (1) {
}
}
// GPIO初始化函数
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置LED引脚为输出
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);
// 配置KEY1引脚为输入,并启用外部中断
GPIO_InitStruct.Pin = KEY1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP; //
HAL_GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
// 使能外部中断
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); //
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 或EXTI0_1_IRQn
}
// TIM2初始化函数
static void MX_TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = (SystemCoreClock / 1000) - 1; // 1kHz计数频率
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000 - 1; // 1秒计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
}
}
时序图:
- 有一个单片机系统中有10位的AD模块,其参考电压为5V,其中的1个通道连接在外部的电阻开关电路中,且PTA0脚连接到外部的LED,如下图。假设AD取值函数int getADVal( )已经存在,请回答如下问题。
注:PTA0可以使用自己熟悉的芯片IO端口替换。
1、计算K1,K2和K1,K2同时按下时AD端口的电压值和对应的AD值。
2、使用函数实现按键采集功能,返回按键的状态。
3、实现短按K1控制LED灯亮(闪烁),再次短按K1控制LED灯灭;
K2控制LED在的慢闪、快闪、长亮三种状态之间顺序切换。
其中 慢闪(亮1秒,灭1秒),快闪(亮0.5秒,灭0.5秒)。
1、闭合k1 电压值2.5V AD值512
闭合k2 电压值10/3V AD值341
同时闭合 电压值0V,AD值0
2、
int getADVal(void);
// 按键状态检测阈值
#define THRESHOLD_LOW 500 // 低电平阈值
#define THRESHOLD_HIGH 900 // 高电平阈值
// 按键采集函数
bool readKeyState(void) {
int adValue = getADVal();
if (adValue > THRESHOLD_HIGH) {
// 高电平,表示按键按下
return true;
} else if (adValue < THRESHOLD_LOW) {
// 低电平,表示按键未按下
return false;
}
}
3、
// 延时函数
void delay_ms(uint32_t ms);
// LED状态枚举
typedef enum {
LED_OFF,
LED_FLASH_SLOW,
LED_FLASH_FAST,
LED_ON
} LEDState;
// 全局变量
static LEDState ledState = LED_OFF;
static time_t lastKey1PressTime = 0;
static bool isKey1Pressed = false;
// 按键采集函数
bool readKeyState(void);
// LED控制函数
void controlLED(void) {
static time_t lastFlashTime = 0;
time_t currentTime = time(NULL); uint32_t elapsedTime = currentTime - lastFlashTime;
// 检测K1按键状态
bool key1State = readKeyState();
if (key1State && !isKey1Pressed) {
// K1刚被按下
isKey1Pressed = true;
lastKey1PressTime = currentTime;
// 切换LED状态
if (ledState == LED_OFF || ledState == LED_FLASH_SLOW || ledState == LED_FLASH_FAST) {
ledState = LED_FLASH_SLOW;
lastFlashTime = currentTime; // 更新闪烁时间
PTA0_WRITE(1); // 点亮LED
} else if (ledState == LED_ON) {
// 如果LED是长亮的,则关闭LED
ledState = LED_OFF;
PTA0_WRITE(0);
}
} else if (!key1State && isKey1Pressed) {
// K1被释放
isKey1Pressed = false;
if (currentTime - lastKey1PressTime < 500) {
if (ledState == LED_FLASH_SLOW || ledState == LED_FLASH_FAST) {
// 如果LED正在闪烁,则关闭LED
ledState = LED_OFF;
PTA0_WRITE(0);
} else if (ledState == LED_ON) {
}
}
// 切换LED状态(慢闪、快闪、长亮之间顺序切换)
switch (ledState) {
case LED_OFF:
ledState = LED_FLASH_SLOW;
break;
case LED_FLASH_SLOW:
ledState = LED_FLASH_FAST;
break;
case LED_FLASH_FAST:
ledState = LED_ON;
break;
case LED_ON:
ledState = LED_OFF;
break;
}
lastFlashTime = currentTime; // 更新闪烁时间(对于长亮状态,这个变量可能不会被使用)
}
- 由于单片机的资源的问题,已经选择的单片机缺少一个串口,需要在单片机的PTA1口上实现串口的数据发送,其中, 假设void delayus(float fTime)微秒延时函数存在。
- 请编写一个函数void UartSend(char ch){},实现对字符型数据ch的发送,其中通讯参数(波特率为9600, 1位停止位,无校验位)。;
- 请编写一个函数void UardSend(char *pStr){},实现对字符串数据的发送功能。
3、如果需要模拟高波特率,如(115200),程序有什么不同?请说明。
1.#include <stdint.h>
void delayus(float fTime);
// UART发送一个字符
void UartSend(char ch) {
// 起始位
PTA1 = 0;
delayus(50);
// 发送8位数据
for (uint8_t i = 0; i < 8; i++) {
if (ch & (1 << (7 - i))) {
PTA1 = 1;
} else {
PTA1 = 0;
}
delayus(104);
}
// 停止位
PTA1 = 1;
delayus(50);
}
2.void UartSendStr(char *pStr) {
while (*pStr) {
UartSend(*pStr++);
}
}
3.void UartSend_115200(char ch) {
// 起始位
PTA1 = 0;
delayus(50);
// 发送8位数据
for (uint8_t i = 0; i < 8; i++) {
if (ch & (1 << (7 - i))) {
PTA1 = 1;
} else {
PTA1 = 0;
}
delayus(87);
}
// 停止位
PTA1 = 1;
delayus(50);
}
// UART发送一个字符串(波特率115200)
void UartSendStr_115200(char *pStr) {
while (*pStr) {
UartSend_115200(*pStr++);
}
}