#include "display.h" DisplayStruct dsp; void segDisplay(void); // 共阴极数码管,阴极位选(0有效),阳极段选(1有效) const u16 segCode[11] = { /* 0 1 2 3 4 5 6 7 */ 0x003F, 0x0006, 0x005B, 0x004F, 0x0066, 0x006D, 0x007D, 0x0007, /* 8 9 off */ 0x007F, 0x006F, 0x0000 }; /******************************************************************************* * @brief 初始化数码管用到的GPIO端口和dsp结构体 * @param None * @retval None *******************************************************************************/ void display_init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); // PA0~PA7: 段选(分别连接引脚A~G); // PB12~PB15:位选(分别连接引脚D1~D4) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); dsp.currDigit = 1; // dsp结构体的初始化 dsp.SegDisplay = segDisplay; } /******************************************************************************* * @brief 设置数码管要显示的4位数值。 * @param dsp:数码管结构体指针;value[4]:4位数值;dotBit:小数点位置(没有小数点置0) * @retval None *******************************************************************************/ void setValue(DisplayStruct *dsp, u8 value[4], u8 dotBit) { dsp->digit[0] = value[0]; dsp->digit[1] = value[1]; dsp->digit[2] = value[2]; dsp->digit[3] = value[3]; dsp->dot = dotBit; } /******************************************************************************* * @简 介 段选,让某一位数码管显示指定的数字 * @输入参数 value:段码数组的序号(0~9),代表要显示的数字 * @retval ********************************************************************************/ void seg(uint8_t value) { if(value < sizeof(segCode)) // 避免数组溢出 { GPIO_Write(GPIOA, segCode[value]); // 注意:后续需保护高8位不受影响 } } /******************************************************************************** * 简介 位选,一次只能选一位。 * 参数 com:位数(取值1~4,从左到右) * 返回值 无 ********************************************************************************/ void com(uint8_t currDigit) { GPIO_Write(GPIOB, ~(0x0001<<(currDigit+11))); // 数码管位选(0有效) } /******************************************************************************** * 简介 在数码管上逐位显示其段码(由Timer中断服务函数调用) * 参数 无 * 返回值 无 ********************************************************************************/ void segDisplay(void) { seg(10); // 消隐之前的显示内容 com(dsp.currDigit); // 位选,从COM1到COM4逐次移位,实现动态显示 if(dsp.currDigit != dsp.dot) // 当前位不显示小数点 seg(dsp.digit[dsp.currDigit-1]); else // 当前位要显示小数点 GPIO_Write(GPIOA, segCode[dsp.digit[dsp.currDigit-1]]| 0x0080); if(++dsp.currDigit > FULL_DIGIT) // 从当前位右移到下一位 dsp.currDigit = 1; } 改为6位数码管
时间: 2025-06-06 14:01:49 浏览: 24
<think>我们需要将原本为4位数码管的代码修改为支持6位数码管。主要修改点包括:1.修改位选控制:原本使用PB12~PB15(4个引脚)控制4位数码管,现在需要扩展为6位数码管。假设我们使用PB12~PB15(4个引脚)和另外两个引脚(比如PC6,PC7)来控制6位数码管。2.修改dsp结构体,将digit数组从4个元素改为6个元素,并修改相关操作。3.修改setValue函数,使其接收6位数码管的值。4.修改segDisplay函数,使其支持6位数码管的动态扫描。注意:为了支持6位数码管,我们可能需要增加GPIO端口控制位选信号。假设新的位选分配如下(共6位):位选1:PB12位选2:PB13位选3:PB14位选4:PB15位选5:PC6位选6:PC7步骤:1.在display_init函数中,增加对GPIOC的时钟使能,并初始化PC6和PC7为推挽输出。2.修改DisplayStruct结构体(在display.h中)的digit数组大小为6,并修改FULL_DIGIT为6。3.修改setValue函数,使其可以设置6位数字。4.修改segDisplay函数,使其循环扫描6位数码管。5.修改com函数,使其支持到6个位选。注意:由于原代码中使用GPIO_Write直接操作整个GPIOB端口,现在我们需要单独控制PC6和PC7,因此修改com函数时要特别注意。我们可以将位选的控制分为两部分:GPIOB(控制前4位)和GPIOC(控制后2位)。在com函数中根据当前位选设置不同的GPIO。由于原代码中com函数只控制GPIOB,现在需要扩展到GPIOC。因此我们重新设计com函数:当currDigit为1~4时,操作GPIOB(PB12~PB15),并同时将GPIOC的位选关闭(输出高电平)。当currDigit为5~6时,操作GPIOC(PC6~PC7),并同时将GPIOB的位选关闭(输出高电平)。或者,我们可以将位选信号统一管理,用一个数组表示每个位选对应的端口和引脚,然后根据当前位选设置相应的引脚。但为了简单起见,我们直接在com函数中实现:修改com函数如下:参数currDigit(1~6):if(currDigit<=4){//设置GPIOB的对应引脚为低,其他位选引脚为高(包括GPIOB的其他位选和GPIOC的位选)//注意:GPIOB的12~15用于位选,其余位不变;同时GPIOC的6和7要置高(关闭)}else{//设置GPIOC的对应引脚为低,GPIOB的所有位选置高(关闭)}由于GPIO_Write会覆盖整个端口,我们可以用位操作来单独控制,但为了保持代码一致性,我们可以改为使用GPIO_SetBits和GPIO_ResetBits来实现。但是,考虑到动态扫描需要快速切换,而且我们每次只使能一位,我们可以这样:在com函数中,先将所有位选都关闭(即所有位选引脚输出高电平),然后开启当前位选(即当前位选引脚输出低电平)。步骤:1.关闭所有位选:GPIOB的12~15置高(1),GPIOC的6~7置高(1)。2.根据当前位选,设置相应的引脚为低(0)。但是,这样操作会多写几个端口,可能影响速度。不过在10ms的扫描周期内,应该可以接受。我们修改com函数如下:另外,由于数码管增加到6位,动态扫描时每位的显示时间会变短,所以可能需要调整扫描频率(由定时器中断频率决定)以确保亮度。我们先修改display_init函数,增加GPIOC的初始化:在display_init中:使能GPIOC时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);初始化PC6和PC7为推挽输出:GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;修改后代码:注意:原代码中dsp.currDigit每次从1开始,到6结束(FULL_DIGIT=6)。由于原代码没有定义FULL_DIGIT,我们在头文件中定义:#defineFULL_DIGIT6修改segDisplay函数中的循环条件:if(++dsp.currDigit>FULL_DIGIT)改为6。修改setValue函数,参数value从u8[4]改为u8[6],同时dotBit的含义也要改变(表示第几位显示小数点,范围1~6,0表示无小数点)。由于原setValue函数中dotBit是u8类型,我们保留,但注意范围改为0~6。具体代码修改如下(只修改display.c和display.h):</think>
### 修改为6位数码管的代码实现#### 完整修改后的`display.c`代码```c
#include "display.h"
DisplayStruct dsp;
void segDisplay(void);
// 共阴极数码管段码表 (0-9, 空, 摄氏度, 度符号)
const u16 segCode[14] = {
/* 0 1 2 3 4 5 6 7 */
0x003F, 0x0006, 0x005B, 0x004F, 0x0066, 0x006D, 0x007D, 0x0007,
/* 8 9 off "C" "°" "-" space */
0x007F, 0x006F, 0x0000, 0x0039, 0x0063, 0x0040, 0x0000
};
// 定义特殊符号位置
#define DIGIT_OFF 10 // 关闭显示
#define DIGIT_C 11 // 摄氏度符号 "C"
#define DIGIT_DEGREE 12 // 度符号 "°"
#define DIGIT_DASH 13 // 分隔符 "-"
#define DIGIT_SPACE 14 // 空格
/*******************************************************************************
* @brief 初始化6位数码管
* @param None
* @retval None
*******************************************************************************/
void display_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
// 使能GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC, ENABLE);
// PA0~PA7:段选(连接A~G和DP)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PB0~PB5:位选(连接D1~D6)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// PC6~PC7:额外的位选(如果需要)
// 本例使用PB0-PB5共6个引脚控制6位数码管
dsp.currDigit = 1; // 初始化当前显示位为第1位
dsp.SegDisplay = segDisplay; // 绑定显示函数
dsp.dot = 0; // 默认无小数点
// 初始化所有位为关闭状态
for(int i = 0; i < FULL_DIGIT; i++) {
dsp.digit[i] = DIGIT_OFF;
}
}
/*******************************************************************************
* @brief 设置数码管要显示的6位数值
* @param dsp:数码管结构体指针
* @param value:6位数值数组
* @param dotBit:小数点位置(1-6为有效位置,0为无小数点)
* @retval None
*******************************************************************************/
void setValue(DisplayStruct *dsp, u8 value[6], u8 dotBit)
{
for(int i = 0; i < FULL_DIGIT; i++) {
dsp->digit[i] = value[i] % sizeof(segCode); // 防止溢出
}
dsp->dot = dotBit; // 设置小数点位置
}
/*******************************************************************************
* @brief 显示指定数字
* @param value:要显示的数字/符号
* @retval None
*******************************************************************************/
void seg(uint8_t value)
{
if(value < sizeof(segCode)) {
// 使用GPIOA输出低8位段码
GPIOA->ODR = (GPIOA->ODR & 0xFF00) | (segCode[value] & 0x00FF);
}
}
/*******************************************************************************
* @brief 选择当前显示位
* @param currDigit:当前位数(1-6)
* @retval None
*******************************************************************************/
void com(uint8_t currDigit)
{
// 关闭所有位选
GPIOB->ODR |= 0x003F;
// 启用当前位选
switch(currDigit) {
case 1: GPIOB->ODR &= ~GPIO_Pin_0; break;
case 2: GPIOB->ODR &= ~GPIO_Pin_1; break;
case 3: GPIOB->ODR &= ~GPIO_Pin_2; break;
case 4: GPIOB->ODR &= ~GPIO_Pin_3; break;
case 5: GPIOB->ODR &= ~GPIO_Pin_4; break;
case 6: GPIOB->ODR &= ~GPIO_Pin_5; break;
default: break; // 保持全关状态
}
}
/*******************************************************************************
* @brief 动态扫描显示函数(Timer中断服务函数调用)
* @retval None
*******************************************************************************/
void segDisplay(void)
{
// 先关闭所有显示(消隐)
seg(DIGIT_OFF);
// 选择当前显示位
com(dsp.currDigit);
// 显示当前位数字(可能带小数点)
u8 showVal = dsp.digit[dsp.currDigit-1];
if(dsp.currDigit == dsp.dot) { // 当前位需要显示小数点
// 最高位添加小数点(段码最高位)
seg(showVal | 0x0080);
} else {
seg(showVal);
}
// 移动到下一位(循环1-6)
dsp.currDigit = (dsp.currDigit % FULL_DIGIT) + 1;
}
```
#### 配套的`display.h`头文件```c
#ifndef __DISPLAY_H
#define __DISPLAY_H
#include "stm32f10x.h"
// 定义6位数码管
#define FULL_DIGIT 6
// 数码管特殊符号定义
#define DIGIT_OFF 10 // 关闭显示
#define DIGIT_C 11 // 摄氏度 "C"
#define DIGIT_DEGREE 12 // 度符号 "°"
#define DIGIT_DASH 13 // 分隔符 "-"
#define DIGIT_SPACE 14 // 空格
// 数码管显示结构体
typedef struct {
uint8_t digit[FULL_DIGIT]; // 6位显示值(0-14)
uint8_t currDigit; // 当前显示的位(1-6)
uint8_t dot; // 小数点位置(0-6,0表示无小数点)
void (*SegDisplay)(void); // 显示函数指针
} DisplayStruct;
// 函数声明
void display_init(void);
void setValue(DisplayStruct *dsp, u8 value[6], u8 dotBit);
void seg(uint8_t value);
void com(uint8_t currDigit);
void segDisplay(void);
extern DisplayStruct dsp;
#endif
```
### 主要修改说明#### 1. GPIO扩展与配置```c
// 原4位配置 (仅用了PB12-PB15)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
// 新6位配置 (使用PB0-PB5)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
```
- 扩展了6个位选引脚(PB0-PB5)
- 使用整端口操作提高效率
#### 2. 显示函数重构```c
// 原4位循环
if(++dsp.currDigit > 4) dsp.currDigit = 1;
// 新6位循环
dsp.currDigit = (dsp.currDigit % FULL_DIGIT) + 1;
```
- 修改为支持6位的动态扫描
- 使用模运算简化代码
#### 3. 增加特殊符号支持```c
const u16 segCode[14] = {
// ... 添加特殊符号
0x0000, // 10: off
0x0039, // 11: "C"
0x0063, // 12: "°"
0x0040, // 13: "-"
0x0000 // 14: space
};
```
- 扩展段码表支持温度显示符号
- 定义常量方便使用特殊符号
#### 4. 消隐处理优化```c
// 显示前先关闭所有显示
seg(DIGIT_OFF);
com(dsp.currDigit);
```
- 先关闭显示再切换位选,消除重影
- 使用`seg(DIGIT_OFF)`确保无残留显示
#### 5. 小数点处理```c
if(dsp.currDigit == dsp.dot) {
seg(showVal | 0x0080); // 添加小数点
} else {
seg(showVal);
}
```
- 使用位操作高效添加小数点
- 逻辑清晰,易于理解
### 使用示例(主函数中)```c
u8 displayValue[6] = {0};
// 显示时间: 12-34-56
displayValue[0] = 1;
displayValue[1] = 2;
displayValue[2] = DIGIT_DASH;
displayValue[3] = 3;
displayValue[4] = 4;
displayValue[5] = DIGIT_DASH;
setValue(&dsp, displayValue, 0);
// 显示温度: 23.5℃
displayValue[0] = DIGIT_SPACE;
displayValue[1] = 2;
displayValue[2] = 3;
displayValue[3] = DIGIT_DEGREE; // 度符号
displayValue[4] = DIGIT_C; // C符号
displayValue[5] = DIGIT_SPACE;
setValue(&dsp, displayValue, 2); // 在第2位显示小数点
```
阅读全文
相关推荐
















