#C0102
沧海茫茫千钟粟,且拾吾昧一微尘
——《沧海拾昧集》@CuPhoenix
【阅前敬告】
沧海拾昧集仅做个人学习笔记之用,所述内容不专业不严谨不成体系
如有问题必是本集记录有谬,切勿深究
目录
一、原理图绘制
![](https://i-blog.csdnimg.cn/blog_migrate/b5f676a748cc9e1ecf257a395cb5f639.png)
图中所用到的元件和元件在库中的名称对照表如下:
元件名 | 库中名称 |
---|---|
可变电阻 | POT-HG |
STM32F103R6 | STM32F103R6 |
4位7段共阴数码管 | 7SEG-MPX4-CC |
高电平 | POWER |
地 | GROUND |
二、多位七段数码管
1、共阴管是CC,共阳管是CA,对应的译码表如下。
![](https://i-blog.csdnimg.cn/blog_migrate/0e58a65f8a7c3c3da56ab0f2d7a4e0b3.jpeg)
2、输入信号A~G、DP的有效信号看是共阴还是共阳,对应的片选信号1~4是低电平有效,从左到右依次为第1位至第4位。
片选位数 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
片选码 | 0x0e00 | 0x0d00 | 0x0b00 | 0x0700 |
3、输出的示例。数字码0x6f,片选码0x0e00,输出码即二者相加0x0e6f。
GPIO_Write(GPIOC, 0x0e6f );
![](https://i-blog.csdnimg.cn/blog_migrate/16ca0d8a9b854dc1c5f1d092242f1116.png)
4、输出用的函数GPIO_Write的定义如下,适用于对统一端口的多个引脚的写入。
void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t ProtVal)
5、多位七段管输出的方法是动态扫描,即逐位输出。在每位输出前面加一个短暂的延时函数,然后清零引脚,动态扫描输出就不会闪烁了。示例如下(在第一位片选码使用0x0e80,加了个小数点)。
先定义好译码表待查。
const uint16_t SegmentCodes[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
const uint16_t SegmentBit[]={0x0e80,0x0d00,0x0b00,0x0700};
输出内容。
uint16_t temp = 1234;
// 输出内容:1234
uint16_t unit[4];
unit[0] = temp / 1000;
unit[1] = temp % 1000 / 100;
unit[2] = temp % 100 / 10;
unit[3] = temp % 10;
// 位数拆分
int i = 0;
for(i=0;i<4;i++){
delay();
GPIO_Write(GPIOC, 0x0f00 );
GPIO_Write(GPIOC, SegmentCodes[unit[i]]+SegmentBit[i] );
}
// 循环输出各位
短暂的延时。
void delay(){
int i=0,j=0;
for(i=0;i<5;i++){
for(j=0;j<100;j++){}
}
}
仿真结果。
![](https://i-blog.csdnimg.cn/blog_migrate/e55c8bf19aad4848d5c560155a4787ea.png)
三、ADC引脚
![](https://i-blog.csdnimg.cn/blog_migrate/9cdeffe94992f3b28150e9a637781edf.jpeg)
图源 @夜路难行々
四、代码
#include "stm32f10x.h"
#define ADC1_DR_Address ((uint32_t)0x4001244C)
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
__IO uint16_t ADCConvertedValue;
ErrorStatus HSEStartUpStatus;
const uint16_t SegmentCodes[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
// 共阴数码管 0 ~ 9 查码表
const uint16_t SegmentBit[]={0x0e80,0x0d00,0x0b00,0x0700};
// 片选 1 ~ 4 查码表
void RCC_Configuration(); // RCC初始化
void GPIO_Configuration(); // GIPO初始化
void delay();
int main(void){
RCC_Configuration();
GPIO_Configuration();
DMA_DeInit(DMA1_Channel1); // DMA初始化
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; // 外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue; // 存储器地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1; // 传输计数器的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 半字
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 自动重装
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 软件触发
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 单ADC触发
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 连续扫描 否
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换 是
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 外部中断 否
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 通道个数
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
// 选择规则组的输入通道,ADC1通道1,采样时钟55.5个周期
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE); // ADC1使能
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1); // 校准ADC
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发ADC
while (1){
uint16_t temp;
int i = 0;
uint16_t unit[4];
temp = (uint16_t)(((double)(ADCConvertedValue) / (double)0xfff ) * (double)3210);
//temp = ADCConvertedValue;
unit[0] = temp / 1000;
unit[1] = temp % 1000 / 100;
unit[2] = temp % 100 / 10;
unit[3] = temp % 10;
for(i=0;i<4;i++){
delay();
GPIO_Write(GPIOC, 0x0f00 );
GPIO_Write(GPIOC, SegmentCodes[unit[i]]+SegmentBit[i] );
}
}
return 0;
}
void RCC_Configuration()
{
SystemInit();
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
#ifndef STM32F10X_CL
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);
#else
RCC_PREDIV2Config(RCC_PREDIV2_Div5);
RCC_PLL2Config(RCC_PLL2Mul_8);
RCC_PLL2Cmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
{}
RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
#endif
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
}
void GPIO_Configuration()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1)
{
}
}
#endif
void delay(){
int i=0,j=0;
for(i=0;i<5;i++){
for(j=0;j<100;j++){}
}
}
五、仿真问题
![](https://i-blog.csdnimg.cn/blog_migrate/e0bbd9b8cf8c249f5c9159b367a47411.png)
仿真遇到问题。无论如何调节输入,ADC的输出均为0。只有在ADC接VDD时,输出为4095(最大值),接与VDD值相等的激励源值也为0。疑似是ADC没有供电。
网上的两种解决方法均无效:
① 如下配置供电网:
供电网 | 网络连接到供电网 |
---|---|
GND | GND / VSS / VSSA |
VCC / VDD(电压3.3V) | VDD / VDDA |
VEE | - |
② 使用高版本的Proteus:有说法8.11可以,8.9不行,但笔者用的8.13也不行。
此问题悬而未决,若有大神路过欢迎赐教!
敬谢诸君。
京华西山之巅。