#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// 衰减档位定义
typedef enum {
DSA_A = 0, // 0dB - A10000010
DSA_B, // -10dB - B00100010
DSA_C, // -20dB - C11110010
DSA_D, // -30dB - D11100010
DSA_E, // -40dB - E10001101
DSA_F, // -50dB - F00101101
DSA_G, // -60dB - G01111101
DSA_H, // -70dB - H11101101
DSA_MAX
} DSALevel_t;
// 衰减配置结构体 (按引脚顺序)
typedef struct {
uint8_t pa4; // bit 0
uint8_t pa3; // bit 1
uint8_t pb0; // bit 2
uint8_t pb1; // bit 3
uint8_t pa8; // bit 4
uint8_t pb15; // bit 5
uint8_t pb13; // bit 6
uint8_t pb14; // bit 7
} DSAConfig_t;
// 函数声明
void SystemClock_Config(void);
void GPIO_Configuration(void);
void USART1_Configuration(void);
void USART1_SendString(const char* str);
void USART1_SendChar(char ch);
void SetAttenuation(DSALevel_t level);
void ShowMenu(void);
void ShowCurrentStatus(DSALevel_t level);
// 全局变量
volatile char rxChar = 0;
volatile uint8_t rxReady = 0;
DSALevel_t currentLevel = DSA_A;
// 衰减配置表
// 引脚顺序:PA4, PA3, PB0, PB1, PA8, PB15, PB13, PB14
const DSAConfig_t DSATable[DSA_MAX] = {
{1, 0, 0, 0, 0, 0, 1, 0}, // A: 10000010 (0dB)
{0, 0, 1, 0, 0, 0, 1, 0}, // B: 00100010 (-10dB)
{1, 1, 1, 1, 0, 0, 1, 0}, // C: 11110010 (-20dB)
{1, 1, 1, 0, 0, 0, 1, 0}, // D: 11100010 (-30dB)
{1, 0, 0, 0, 1, 1, 0, 1}, // E: 10001101 (-40dB)
{0, 0, 1, 0, 1, 1, 0, 1}, // F: 00101101 (-50dB)
{0, 1, 1, 1, 1, 1, 0, 1}, // G: 01111101 (-60dB)
{1, 1, 1, 0, 1, 1, 0, 1}, // H: 11101101 (-70dB)
};
// 档位名称和衰减值
const char* levelNames[DSA_MAX] = {"A", "B", "C", "D", "E", "F", "G", "H"};
const int DSAValues[DSA_MAX] = {0, -10, -20, -30, -40, -50, -60, -70};
int main(void)
{
// 系统初始化
SystemClock_Config();
GPIO_Configuration();
USART1_Configuration();
// 延时等待系统稳定
for(volatile int i = 0; i < 1000000; i++);
// 初始化为A档(0dB)
SetAttenuation(DSA_A);
// 显示欢迎信息和菜单
ShowMenu();
ShowCurrentStatus(currentLevel);
while(1)
{
// 处理接收到的字符
if(rxReady)
{
rxReady = 0;
char input = toupper(rxChar); // 转换为大写
// 回显输入字符
USART1_SendChar(input);
USART1_SendString("\r\n");
// 解析命令
switch(input)
{
case 'A':
currentLevel = DSA_A;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'B':
currentLevel = DSA_B;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'C':
currentLevel = DSA_C;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'D':
currentLevel = DSA_D;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'E':
currentLevel = DSA_E;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'F':
currentLevel = DSA_F;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'G':
currentLevel = DSA_G;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'H':
currentLevel = DSA_H;
SetAttenuation(currentLevel);
ShowCurrentStatus(currentLevel);
break;
case 'M': // 显示菜单
ShowMenu();
ShowCurrentStatus(currentLevel);
break;
case 'S': // 显示状态
ShowCurrentStatus(currentLevel);
break;
default:
USART1_SendString("ERROR: Invalid command! Press 'M' for menu.\r\n\n");
break;
}
}
}
}
/**
* @brief 系统时钟配置: 72MHz
*/
void SystemClock_Config(void)
{
ErrorStatus HSEStartUpStatus;
// 复位RCC时钟配置
RCC_DeInit();
// 使能外部高速时钟(HSE)
RCC_HSEConfig(RCC_HSE_ON);
// 等待HSE就绪
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
// 使能FLASH预取缓冲
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// Flash 2个等待周期
FLASH_SetLatency(FLASH_Latency_2);
// AHB时钟 = 系统时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// APB2时钟 = AHB时钟
RCC_PCLK2Config(RCC_HCLK_Div1);
// APB1时钟 = AHB时钟/2
RCC_PCLK1Config(RCC_HCLK_Div2);
// PLLCLK = 8MHz * 9 = 72MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
// 使能PLL
RCC_PLLCmd(ENABLE);
// 等待PLL就绪
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 选择PLL作为系统时钟源
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 等待PLL被选择为系统时钟源
while(RCC_GetSYSCLKSource() != 0x08);
}
}
/**
* @brief GPIO配置
*/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 必须使能 GPIOA 和 GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 配置所有用到的引脚为推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIOA: PA3, PA4, PA8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_8;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// GPIOB: PB0, PB1, PB13, PB14, PB15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 初始化所有控制引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_8);
GPIO_ResetBits(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
/**
* @brief USART1配置
*/
void USART1_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能GPIOA和USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 |
RCC_APB2Periph_AFIO, ENABLE);
// 配置PA9 (USART1_TX) 为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PA10 (USART1_RX) 为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1配置: 115200 8N1
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 配置USART1中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
/**
* @brief USART1发送字符串
*/
void USART1_SendString(const char* str)
{
while(*str)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, *str++);
}
}
/**
* @brief USART1发送单个字符
*/
void USART1_SendChar(char ch)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
}
/**
* @brief 设置衰减等级
* @param level: 衰减档位 (DSA_A ~ DSA_H)
*/
void SetAttenuation(DSALevel_t level)
{
if(level >= DSA_MAX) return;
const DSAConfig_t* config = &DSATable[level];
// 按照配置设置各个引脚
// 引脚顺序: PA4, PA3, PB0, PB1, PA8, PB15, PB13, PB14
if(config->pa4)
GPIO_SetBits(GPIOA, GPIO_Pin_4);
else
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
if(config->pa3)
GPIO_SetBits(GPIOA, GPIO_Pin_3);
else
GPIO_ResetBits(GPIOA, GPIO_Pin_3);
if(config->pb0)
GPIO_SetBits(GPIOB, GPIO_Pin_0);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
if(config->pb1)
GPIO_SetBits(GPIOB, GPIO_Pin_1);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
if(config->pa8)
GPIO_SetBits(GPIOA, GPIO_Pin_8);
else
GPIO_ResetBits(GPIOA, GPIO_Pin_8);
if(config->pb15)
GPIO_SetBits(GPIOB, GPIO_Pin_15);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_15);
if(config->pb13)
GPIO_SetBits(GPIOB, GPIO_Pin_13);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_13);
if(config->pb14)
GPIO_SetBits(GPIOB, GPIO_Pin_14);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_14);
for(volatile uint32_t i = 0; i < 100; i++) __NOP(); // 延时约几微秒
}
/* 显示菜单
*/
void ShowMenu(void)
{
USART1_SendString("\r\n");
USART1_SendString("========================================\r\n");
USART1_SendString(" STM32 Attenuator Controller v1.0\r\n");
USART1_SendString("========================================\r\n");
USART1_SendString("Attenuation Levels (10dB steps):\r\n");
USART1_SendString(" A: 0dB (10000010)\r\n");
USART1_SendString(" B: -10dB (00100010)\r\n");
USART1_SendString(" C: -20dB (11110010)\r\n");
USART1_SendString(" D: -30dB (11100010)\r\n");
USART1_SendString(" E: -40dB (10001101)\r\n");
USART1_SendString(" F: -50dB (00101101)\r\n");
USART1_SendString(" G: -60dB (01111101)\r\n");
USART1_SendString(" H: -70dB (11101101)\r\n");
USART1_SendString("\r\n");
USART1_SendString("Commands:\r\n");
USART1_SendString(" A-H: Select attenuation level\r\n");
USART1_SendString(" M: Show this menu\r\n");
USART1_SendString(" S: Show current status\r\n");
USART1_SendString("========================================\r\n");
USART1_SendString("Pin Order: PA4, PA3, PB0, PB1, PA8, PB15, PB13, PB14\r\n");
USART1_SendString("========================================\r\n\n");
}
/* 显示当前状态
*/
void ShowCurrentStatus(DSALevel_t level)
{
char buffer[128];
const DSAConfig_t* config = &DSATable[level];
sprintf(buffer, "Current Level: %s (%d dB)\r\n",
levelNames[level], DSAValues[level]);
USART1_SendString(buffer);
sprintf(buffer, "Pin States: [%d%d%d%d%d%d%d%d]\r\n",
config->pa4, config->pa3, config->pb0, config->pb1,
config->pa8, config->pb15, config->pb13, config->pb14);
USART1_SendString(buffer);
USART1_SendString("Ready> ");
}
/* USART1中断服务函数
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
rxChar = USART_ReceiveData(USART1);
rxReady = 1;
}
}