【南航嵌入式系统原理与应用】第7章作业

第七章作业

7-1 基于嵌入式处理器的模拟输入输出系统是怎么构成的?各部分的主要功能是什么?两个系统的主要区别是什么

答案:

  • 与模拟输入输出系统的区别:嵌入式内部已经大都集成了A/D转换器、D/A转化器。其他的和普通模拟输入输出系统相同。
  • 嵌入式处理器的模拟输入输出系统示意图
    image-20220416201708980
  • 传感器:感知或采集工程过程中的相关参数,如温度、压力、流量等
  • 信号调理电路:把传感器送来的信号进行调整处理,使采集的信号在A/D的有效范围
  • A/D变换器:将模拟信号转换为数字信号
  • 处理器:对变换后的数字信号根据系统需求进行数字处理或运算
  • D/A变换器:将数字信号变成模拟信号
  • 功率放大:把模拟信号进行功率放大,使之自已推动后面的执行机构
  • 执行机构:将电能变换为机械能或其它能量以控制工业过程
7-5 信号滤波有哪些基本类型?各种滤波电路有何特点?

答案:

  • 信号滤波主要的类型及特点
    • 高通滤波器:只能通过高频,中低频被阻止通过
    • 低通滤波器:只能通过低频,中高频率的信号被阻止
    • 带通滤波器:仅允许中间频率通过,⾼低频率被阻止
    • 带阻滤波器:仅允许⾼低频通过,中间频率段被阻⽌
7-12 对于 STM32F10x 微控制器,使用片上 ADC 通道 3(PA3 作为 ADCIN3)作为电位器位置检测的一个实例,如图 7.41 所示。当旋转电位器 VR1 时,ADCIN3 随之电压发生变化,如果电位代表位置,假设 0V表示位置 0 米,3.3V 表示 100 米,当电位器从最低端向最高端旋转时,电位从 0 到 3.3V 变化,也即位置从 0 到 100 米线性变化。试回答:

image-20220416204235218

(1)写出对片上 DAC 的初始化程序片段(含引脚配置及 DAC 初始化)
(2)写出采集电位并进行标度变换的程序。

答案:

(1)写出对片上 DAC 的初始化程序片段(含引脚配置及 DAC 初始化)

void ADC_Configuration(void) //配置和初始化 ADC
{
    GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|
    RCC_APB2Periph_ADC1,ENABLE);//A口及A口多功能时钟选择(PA3为ADCIN3)
    /* 配置GPIO的PA7作为ADCIN3模拟通道输入端,频率50MHz */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_GPIO_Pin_3;//ADC1通道PA3=ADIN3引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO端口
    /* 初始化ADC:独立模式、多通道扫描、连续转换、软件触发、ADC数据右对齐 */
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立工作模式
    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数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;//进行规则转换的ADC通道数为1个通道
    ADC_Init(ADC1, &ADC_InitStructure);
    /* 设置ADC1使用ADCIN7转换通道,转换顺序1,采样时间为239.5周期*/ 
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5 );
    ADC_Cmd(ADC1, ENABLE); //使能ADC1
    ADC_ResetCalibration(ADC1); //使能ADC1复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准寄存器接收
   	ADC_StartCalibration(ADC1); //启动ADC1校准
    while(ADC_GetCalibrationStatus(ADC1)); //等待ADC1校准结束
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动软件转换
 }

(2)写出采集电位并进行标度变换的程序

答案:

uint16_t Temp;
float Valtage;//电压值
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
Temp = ADC_GetConversionValue(ADC1); //调用库函数获取转换值
/*假设在由电位器电位可知,当V=0V时,测算的数字量为N0=0,V=3.3V=3300mV时测算的
数字量为Nm=0xFFF,则通过标度变换公式(7.2)得到任何数字对应的电压值为:
Yx=Y0+(Ym-Y0)*(Nx-N0)/(Nm-N0)=0+3300*Nx/0xFFF=3300Nx/0xFFF (mV)*/
Valtage=3300*Temp/0xFFF;//压力换算值,单位mV
7-14 简述利用片内 DAC 再通过外加运算放大电路产生指定幅度和周期的正弦波的方法和步骤。写出对STM32F10x 的 DAC 进行配置和初始化的程序片段。

(1)简述利用片内 DAC 再通过外加运算放大电路产生指定幅度和周期的正弦波的方法和步骤

答案:

​ 利用 DAC 通过外接运放产生幅度可变,周期可编程的正弦波的基本方法是首先采集一个周期正弦波的平均 N 个点如 32 个点的幅值,保存在程序存储器中或数据存储器中,然后利用定时器定时,定时长度取决于正弦波的周期,如周期为 T,则定时时间间隔 t=T/(N-1),在定时中断服务程序中输出保存在存储器中正弦的瞬时幅值,设置好初值指针,每定时时间到输出一个点,指针加一,通过(N-1)次定时中断即可输出一个周期的正弦波,当指针回零时,继续定时中断即可输出连续的正弦波。由 DAC 输出特点可知,它是 12 位 DAC,因此输出电压 Vo= DAC 输出= VREFx (DOR / 4095),在参考电压一定的情况下,输出大小取决于数字量,将公式变换为:

​ Vo=K*Dx/4095,Dx 为保存在存储器中的要输出的正弦波的点的值,K 已经考虑了参考电压,运放放大倍数等因素,因此要控制正弦波幅值只需要在程序中改变 K 的大小,而要改变正弦波的周期,只需要改变定时时间间隔。

(2)程序片段

​ 对于 STM32F10x 的 DAC 可进行如下配置:DAC 初始化包括 GPIO 引脚初始化为 DAC 引脚和 DAC 相应配置。GIO 初始化包括使能对应 DAC 通道的 GPIO 引脚时钟,使能 DAC 时钟,设置通道引脚为模拟输入。一旦使能 DACx 通道,相应的 GPIO 引脚(通道 1 的 PA4 或者通道 2 的 PA5)就会自动与 DAC 的模拟输出相连(DAC_OUT1 或 DAC_OUT2)。为了避免寄生的干扰和额外的功耗,引脚 PA4 或者 PA5 在之前应当设置成模拟输入(AIN)。

​ DAC 初始化包括选择触发方式、是否使用波形发生、关闭输出缓冲、使能 DAC、通道 1 或 2 由软件触发。设置通道 12 位右对齐模式。

​ 具体初始化及配置程序如下:

答案:

void DAC_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    DAC_InitTypeDef DAC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC ,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
    RCC_APB2Periph_AFIO,ENABLE); 
    /*-----------DAC 端口配置 PA4/PA5 DAC1 通道 4 模拟输入-------------*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA ,&GPIO_InitStructure);
    DAC_DeInit(); //还原到初始状态
    /* DAC 通道 1 配置 */
    DAC_InitStructure.DAC_Trigger = DAC_Trigger_T3_TRGO; //T3 触发
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不用波形产生
    DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //失能输出缓冲
    DAC_Init(DAC_Channel_1, &DAC_InitStructure); //DAC 初始化
    DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC 通道 1 自动连接至 PA4
    DAC_SetChannel1Data(DAC_Align_12b_R,0);//通道 1 右对齐输出
}
7-15 试设计一个模拟输入输出系统,采用 STM32F10x 微控制器,采用 3.3V 供电,内置 12 位 ADC,某压力传感器输出 0-100mV 对于 0-10Mpa,压力超过 8.5Mpa 时,输出报警信号,让蜂鸣器发声,低于 8Mpa时解除报警。并将得到的压力用 4-20mA 电流输出到外部。写出相关程序片段。

答案:

按照题目要求,基于 STM32F10x 的模拟输入输出系统,必须包括模拟输入通道和模拟输出通道,系统电原理图如图所示。

image-20220417130349932

模拟输入通道要将压力传感器 0-100mV 的电压信号通过调理电路(放大滤波)到 0-3.3V,因此运算放大器 U1B 放大倍数应该为 3300/100=33 倍,这里采用同相放大器,则 Rf/R1=32,如果取 R1=1K,由 Rf=32K,采用 U1A 构建的二阶有源低通滤波器,最后通过调电路输出的模拟信号接入 ADCIN1(MCU 的 PA1 引脚)。

模拟输出通道输出 4~20mA 电路,参考教材中的图 7.33。

报警输出电路由 R9/BG2/蜂鸣器组成,当 PB1(Ctrl)=1 时,三极管 BG2 导通,BJ 蜂鸣器得电发声报警,当 PB1=0 时三极管截止,蜂鸣器不响,停止报警。报警点是 8MPa,由线性标度变换可知:100mV 经过放大 33 倍后变成 3.3V,由于参考电压也是 3.3V 因此,数字量为 0xFFF=4095,由此可知:P=10/4095*Dx,Dx 为从 ADC 转换得到的数字量,把压力单位变换为 Kpa,则有
P=10000/4095*Dx (Kpa),Dx=4095*P/10000,l 因此当 8.5Mpa 时,有 D=4095/10000*8500 为报警点。
Yx=Ym-Y0+(Ym-Y0)(Nx-N0)/(Nm-N0)=4+16*(Nx-496)/(2482-496)

相关程序如下:
ADC 初始化程序详见教材 P.230,把其中的 ADCIN7 改为 ADCIN1,PA7 改为 PA1,GPIO_Pin_7 改为
GPIO_Pin_1,ADC_Channel_7 改为 ADC_Channel_1,其它不变

void ADC_Configuration(void) //配置和初始化ADC
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|
    RCC_APB2Periph_ADC1,ENABLE);//A口及A口多功能时钟选择(PA7为ADCIN7)
    /* 配置GPIO的PA1作为ADCIN1模拟通道输入端,频率50MHz */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_GPIO_Pin_1;//ADC1通道PA1=ADIN1引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO端口
    /* 初始化ADC:独立模式、多通道扫描、连续转换、软件触发、ADC数据右对齐 */
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立工作模式
    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数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;//进行规则转换的ADC通道数为1个通道
    ADC_Init(ADC1, &ADC_InitStructure);
    /* 设置ADC1使用ADCIN1转换通道,转换顺序1,采样时间为239.5周期*/ 
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );
    ADC_Cmd(ADC1, ENABLE); //使能ADC1
    ADC_ResetCalibration(ADC1); //使能ADC1复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准寄存器接收
    ADC_StartCalibration(ADC1); //启动ADC1校准
    while(ADC_GetCalibrationStatus(ADC1)); //等待ADC1校准结束
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动软件转换
}

DAC 初始化程序 详见教材 P.236,这里由于使用的通道均为 DAC1 即用 PA4 引脚,程序不用修改直接引用。具体程序如下:

void DAC_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    DAC_InitTypeDef DAC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC ,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO,ENABLE); 
	/*-----------DAC 端口配置 PA4/PA5 DAC1 通道 1 模拟输入-------------*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA ,&GPIO_InitStructure);
    DAC_DeInit(); //还原到初始状态
    /* DAC 通道 1 配置 */
    DAC_InitStructure.DAC_Trigger = DAC_Trigger_T3_TRGO; //T3 触发
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不用波形产生
    DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //失能输出缓冲
    DAC_Init(DAC_Channel_1, &DAC_InitStructure); //DAC 初始化
    DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC 通道 1 自动连接至 PA4
    DAC_SetChannel1Data(DAC_Align_12b_R,0);//通道 1 右对齐输出
}

将压力转换成 4-20mA 的电流,0Mpa 对应 4mA,10Ma 对应 20mA,要通过图示电路输出 4mA 时,需要从 DAC 输出 0.4V 电压,因此对应数字量为 0.4*4095/3.3=496输出 20mA 要求 DAC 输出的电压为 2V,因此数字量为 2*4095/3.3=2482,

按照线性标度变换可知:

N0=496,Nm=2482,Ym=20,Y0=4,Yx=Ym-Y0+(Ym-Y0)(Nx-N0)/(Nm-N0)=4+16*(Nx-496)/(2482-496)

Yx=4+16(Nx-496)/1986 ,Nx>=496

现在看输出与输入的关系:输入 0 时放大后也是 Din0=0,对应 ADC 数字量 0,输出应该 4mA,电压为 0.4V,数字量 Dout0=496,输入 100mV 放大后 3.3V 时对应 ADC 数字量 Dinm=4095,输出应该是 20mA,输出电压为 2V,对应数字量为Doutm=2482,

输入任何电压(放大后)对应数字量 Doutx 为:

Doutx=Dout0+(Doutm-Dout0)*(Dinx-0)/(Dinm-Din0)=496+(2482-496)Dinx/4095=496+1986Dinx/4095

Doutx=496+1986Dinx/4095,用 Doutx 代入上述 Yx 的 Nx 得:

Yx=4+16(496+1986Dinx/4095-496)/1986

Yx=4+16*Dinx/4095,显示当 Dinx=0 时输出 4mA,Dinx=4095 时输出 20mA,编程时,只需要通过 DAC 输出 Doutx=496+1986Dinx/4095 即可输出 4-20mA 电流,其中 Dinx 为采集压力信号对应的数字量。

main()
{
    float P_Value;//压力值,单位 Kpa
	uint16_t DataIn,DataOut;
	:系统初始化、ADC 初始化、DAC 初始化、PB1 初始化为推挽输出初始化
	while(1)
    {
    	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
   		DataIn = ADC_GetConversionValue(ADC1); //获取转换值
        P_Value=10000/4095*DataIn;//压力换算值,单位 Kpa
        if (P_Value>8500) GPIO_SetBits(GPIOB,GPIO_Pin_1);//报警输出蜂鸣器响
        else GPIO_ResetBits(GPIOB,GPIO_Pin_1);//报警输出撤消,蜂鸣器停止响声
        DataOut=496+1986Dinx/4095;//取待输出的数字量(与输入对应的电压通过电流转换为 4-20mA 电流)
        DAC_SetChannel1Data(DAC_Align_12b_R, DataOut);//以 12 位右对齐方式输出 Value 数字量
    }
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NUAA_Peter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值