5、flash相关、adc和dac

flash闪存,可以一种可编程式存储器

 

flash结构体定义

typedef struct
{
  __IO uint32_t ACR;              /*!< FLASH access control register,            Address offset: 0x00 */ 访存控制器
  __IO uint32_t PDKEYR;           /*!< FLASH power down key register,            Address offset: 0x04 */ 
  __IO uint32_t KEYR;             /*!< FLASH key register,                       Address offset: 0x08 */
  __IO uint32_t OPTKEYR;          /*!< FLASH option key register,                Address offset: 0x0C */
  __IO uint32_t SR;               /*!< FLASH status register,                    Address offset: 0x10 */ 状态寄存器
  __IO uint32_t CR;               /*!< FLASH control register,                   Address offset: 0x14 */
  __IO uint32_t ECCR;             /*!< FLASH ECC register,                       Address offset: 0x18 */
  __IO uint32_t RESERVED1;        /*!< Reserved1,                                Address offset: 0x1C */
  __IO uint32_t OPTR;             /*!< FLASH option register,                    Address offset: 0x20 */
  __IO uint32_t PCROP1SR;         /*!< FLASH bank1 PCROP start address register, Address offset: 0x24 */
  __IO uint32_t PCROP1ER;         /*!< FLASH bank1 PCROP end address register,   Address offset: 0x28 */
  __IO uint32_t WRP1AR;           /*!< FLASH bank1 WRP area A address register,  Address offset: 0x2C */
  __IO uint32_t WRP1BR;           /*!< FLASH bank1 WRP area B address register,  Address offset: 0x30 */
} FLASH_TypeDef;

 

 

核心api:

  flash_init, flash_erase, flash_write, flash_read_logic

 

//包含头文件
#include "flash.h"
#include "string.h"
#if(USE_BIOS_FLASH==0)//1代表函数继承自BIOS,0代表使用自带函数
//=================内部调用函数声明=====================================
//======================================================================
//函数名称:flash_write_DoubleWord
//函数返回:0-成功 1-失败
//参数说明:addr:目标地址,要求为4的倍数且大于Flash首地址
//              (例如:0x08000004,Flash首地址为0x08000000)
//       data:写入的双字
//功能概要:Flash双字写入操作
//======================================================================
uint8_t flash_write_DoubleWord(uint32_t addr,uint32_t data_l,uint32_t data_h);
//======================================================================
//函数名称:flash_Best
//函数返回:0-成功 1-失败
//参数说明:sect:待写入扇区号
//            offset:待写入数据位置的偏移地址
//            N:待写入数据字节数
//            buf:待写入数据的首地址
//功能概要:首位地址都对齐的情况下的数据写入
//======================================================================
uint8_t flash_Best(uint16_t sect,uint16_t offset,uint16_t N,uint8_t *buf);
//======================================================================
//======================================================================

//=================外部接口函数=========================================
//======================================================================
//函数名称:flash_init
//函数返回:无
//参数说明:无
//功能概要:初始化flash模块
//编程来源:暂无
//======================================================================
void flash_init(void)
{
    //(1)清除之前的编程导致的所有错误标志位
    FLASH->SR &= 0xFFFFFFUL;
    //(2)解锁Flash控制寄存器(CR)
    if((FLASH->CR & FLASH_CR_LOCK) != 0U)
    {
        FLASH->KEYR = (uint32_t)FLASH_KEY1;
        FLASH->KEYR = (uint32_t)FLASH_KEY2;
    }
    //(3)等待解锁操作成功
    while((FLASH->CR & FLASH_CR_LOCK) != 0U);
    //(4)等待之前最后一个flash操作完成
    while( (FLASH->SR & FLASH_SR_BSY) != 0U);
    //(5)清数据缓冲区
  /*

    #define FLASH_ACR_DCEN_Pos (10U)
    #define FLASH_ACR_DCEN_Msk (0x1UL << FLASH_ACR_DCEN_Pos) /*!< 0x00000400 */ (DataCacheEnable,数据缓存使能位)

  */
FLASH->ACR &= ~FLASH_ACR_DCEN_Msk; //(6)清闪存即时编程位 FLASH->CR &= ~FLASH_CR_PG_Msk; } //====================================================================== //函数名称:flash_erase //函数返回:函数执行执行状态:0=正常;1=异常。 //参数说明:sect:目标扇区号(范围取决于实际芯片,例如 STM32L433:0~127,每扇区2KB; //功能概要:擦除flash存储器的sect扇区 //编程参考:STM32L4Rxxx芯片手册3.3.6主存储器擦除顺序 //====================================================================== uint8_t flash_erase(uint16_t sect) { //(1)等待之前最后一个flash操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); //(2)清除之前的编程导致的所有错误标志位 FLASH->SR &= 0xFFFFFFUL; //(3)清闪存即时编程位,将 PER 位置 1,并选择要擦除的页 (PNB)和相关存储区 (BKER) FLASH->CR &= ~FLASH_CR_PG; FLASH->CR |= FLASH_CR_PER; FLASH->CR &= ~FLASH_CR_PNB; FLASH->CR |= (uint32_t)(sect << 3u); //(4)将 FLASH_CR 寄存器中的 STRT 位置 1,开始扇区擦除 FLASH->CR |= FLASH_CR_STRT; //(5)等待 FLASH_SR 寄存器中的 BSY 位清零,等待擦除操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); FLASH->CR &= ~FLASH_CR_PER; return 0; //成功返回 } //====================================================================== //函数名称:flash_write //函数返回:函数执行状态:0=正常;1=异常。 //参数说明:sect:扇区号(范围取决于实际芯片,例如 STM32L433:0~127,每扇区2KB) // offset:写入扇区内部偏移地址(0~2044,要求为0,4,8,12,......) // N:写入字节数目(4~2048,要求为4,8,12,......) // buf:源数据缓冲区首地址 //功能概要:将buf开始的N字节写入到flash存储器的sect扇区的 offset处 //编程参考:暂无 //======================================================================= uint8_t flash_write(uint16_t sect,uint16_t offset,uint16_t N,uint8_t *buf) { //(1)定义变量 uint16_t i; //(2)清除之前的编程导致的所有错误标志位 FLASH->SR &= 0xFFFFFFUL; //(3.1)写入字节数后会跨扇区 if(offset+N>MCU_SECTORSIZE) { //(3.1.1)先写入第一个扇区 flash_write(sect,offset,MCU_SECTORSIZE-offset,buf); //(3.1.2)再写入第二个扇区 flash_write(sect+1,0,N-(MCU_SECTORSIZE-offset),buf+(MCU_SECTORSIZE-offset)); } //(3.2)写入字节数不会跨扇区 else { uint8_t data[MCU_SECTORSIZE]; //存储当前扇区的全部值 flash_read_logic(data,sect,0,MCU_SECTORSIZE); //将当前扇区的全部值读入数组中 //将要写入的数据依照对应位置写入数组中 for(i = 0;i<N;i++) { data[offset+i] = buf[i]; } //擦除扇区 flash_erase(sect); //将数组写入扇区 flash_Best(sect,0,MCU_SECTORSIZE,data); } //(4)等待写入操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); return 0; //成功执行 } //========================================================================== //函数名称:flash_write_physical //函数返回:函数执行状态:0=正常;非0=异常。 //参数说明: addr:目标地址,要求为4的倍数且大于Flash首地址 // (例如:0x08000004,Flash首地址为0x08000000) // cnt:写入字节数目(8~512) // buf:源数据缓冲区首地址 //功能概要:flash写入操作 //编程参考:暂无 //========================================================================== uint8_t flash_write_physical(uint32_t addr,uint16_t N,uint8_t buf[]) { //(1)定义变量。sect-扇区号,offset-扇区地址 uint16_t sect; //扇区号 uint16_t offset; // 偏移地址 //(2)变量赋值,将物理地址转换为逻辑地址(扇区和偏移量) sect = (addr-MCU_FLASH_ADDR_START)/MCU_SECTORSIZE; offset = addr-(sect*MCU_SECTORSIZE)-MCU_FLASH_ADDR_START; //(3)调用写入函数写入数据 flash_write(sect,offset,N,buf); //(4)等待写入操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); return 0; //成功执行 } //====================================================================== //函数名称:flash_read_logic //函数返回:无 //参数说明:dest:读出数据存放处(传地址,目的是带出所读数据,RAM区) // sect:扇区号(范围取决于实际芯片,例如 STM32L433:0~127,每扇区2KB) // offset:扇区内部偏移地址(0~2024,要求为0,4,8,12,......) // N:读字节数目(4~2048,要求为4,8,12,......)// //功能概要:读取flash存储器的sect扇区的 offset处开始的N字节,到RAM区dest处 //编程参考:暂无 //======================================================================= void flash_read_logic(uint8_t *dest,uint16_t sect,uint16_t offset,uint16_t N) { //(1)定义变量。src-读取的数据的地址 uint8_t *src; //(2)变量赋值。通过扇区号和偏移量计算出逻辑地址 src=(uint8_t *)(FLASH_BASE+sect*FLASH_PAGE_SIZE+offset); //(3)读出数据 memcpy(dest,src,N); } //====================================================================== //函数名称:flash_read_physical //函数返回:无 //参数说明:dest:读出数据存放处(传地址,目的是带出所读数据,RAM区) // addr:目标地址,要求为4的倍数(例如:0x00000004) // N:读字节数目(0~1020,要求为4,8,12,......) //功能概要:读取flash指定地址的内容 //编程参考:暂无 //====================================================================== void flash_read_physical(uint8_t *dest,uint32_t addr,uint16_t N) { //(1)定义变量。src-读取的数据的地址 uint8_t *src; //(2)变量赋值。直接使用物理地址 src=(uint8_t *)addr; //(3)读出数据 memcpy(dest,src,N); } //====================================================================== //函数名称:flash_protect //函数返回:无 //参数说明:M:待保护的扇区号 //功能概要:flash保护操作 //编程参考:暂无 //====================================================================== void flash_protect(uint8_t M) { //(1)定义变量。temp-配置所用值 uint32_t temp; //(2)变量赋值。 temp = M|((M+1)<<16); //(3)对保护区进行锁定 if((FLASH->CR & FLASH_CR_OPTLOCK) != 0U) { FLASH->OPTKEYR = (uint32_t)FLASH_OPTKEY1; FLASH->OPTKEYR = (uint32_t)FLASH_OPTKEY2; } //(4)等待锁定成功 while((FLASH->CR & FLASH_CR_OPTLOCK) != 0U); //(5)等待 FLASH_SR 寄存器中的 BSY 位清零,等待擦除操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); //(6)配置相关寄存器 FLASH->WRP1AR &= 0x0; FLASH->WRP1AR |= temp; FLASH->CR |= FLASH_CR_OPTSTRT; //(7)等待 FLASH_SR 寄存器中的 BSY 位清零,等待擦除操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); FLASH->CR &= ~FLASH_CR_OPTSTRT; } //====================================================================== //函数名称:flash_unprotect //函数返回:无 //参数说明:M:待解保护的扇区号 //功能概要:flash解保护操作 //说明: //编程参考:暂无 //====================================================================== void flash_unprotect(uint8_t M) { //(1)定义变量。temp-配置所用值 uint32_t temp; //(2)变量赋值。 temp = 0xff00ffff; //(3)对保护区进行锁定 if((FLASH->CR & FLASH_CR_OPTLOCK) != 0U) { FLASH->OPTKEYR = (uint32_t)FLASH_OPTKEY1; FLASH->OPTKEYR = (uint32_t)FLASH_OPTKEY2; } //(4)等待 FLASH_SR 寄存器中的 BSY 位清零,等待操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); //(5)配置相关寄存器 FLASH->WRP1AR &= 0x0; FLASH->WRP1AR |= temp; FLASH->CR |= FLASH_CR_OPTSTRT; //(6)等待 FLASH_SR 寄存器中的 BSY 位清零,等待操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); FLASH->CR &= ~FLASH_CR_OPTSTRT; } //====================================================================== //函数名称:flash_isempty //函数返回:1=目标区域为空;0=目标区域非空。 //参数说明:所要探测的flash区域初始地址 //功能概要:flash判空操作 //编程来源:暂无 //====================================================================== uint8_t flash_isempty(uint16_t sect,uint16_t N) { //(1)定义变量flag-操作成功标志,src-目标地址,dest[]-暂存数据 uint16_t i,flag; uint8_t dest[N]; uint8_t *src; //(2)变量赋值并读取数据 flag = 1; src=(uint8_t *)(FLASH_BASE+sect*FLASH_PAGE_SIZE); memcpy(dest,src,N); //(3)判断区域内数据是否为空 for(i = 0; i<N; i++) //遍历区域内字节 { if(dest[i]!=0xff) //非空 { flag=0; break; } } return flag; } //======================================================================== //函数名称:flashCtl_isSectorProtected //函数返回:1=扇区被保护;0=扇区未被保护 //参数说明:所要检测的扇区 //功能概要:判断flash扇区是否被保护 //编程参考:暂无 //========================================================================= uint8_t flash_isSectorProtected(uint16_t sect) { //(1)定义变量。STRT-扇区开始号,END-扇区结束号,temp-暂存值 uint8_t STRT,END; uint32_t temp; //(2)查看扇区是否被保护 temp = FLASH->WRP1AR; STRT = temp; END = temp>>16; if(sect>=STRT && sect<END) return 1; //(3)查看扇区是否被保护 temp = FLASH->WRP1BR; STRT = temp; END = temp>>16; if(sect>=STRT && sect<END) return 1; return 0; } //----------------------以下为内部函数存放处---------------------------- //====================================================================== //函数名称:flash_write_DoubleWord //函数返回:0-成功 1-失败 //参数说明:addr:目标地址,要求为4的倍数且大于Flash首地址 // (例如:0x08000004,Flash首地址为0x08000000) // data:写入的双字 //功能概要:Flash双字写入操作(STM32L433每次只能实现双字写入,先写低位字,再写高位字) //编程参考:暂无 //====================================================================== uint8_t flash_write_DoubleWord(uint32_t addr,uint32_t data_l,uint32_t data_h) { //(1)清数据缓冲区 if((FLASH->ACR & FLASH_ACR_DCEN) != 0U) { FLASH->ACR &= ~FLASH_ACR_DCEN; } //(2)使能Flash即时编程 FLASH->CR |= FLASH_CR_PG; //(3.1)先写入低位字 *(__IO uint32_t*)addr = data_l; //(3.2)再写入高位字 *(__IO uint32_t*)(addr+4U) = data_h; //(4)禁止Flash即时编程 FLASH->CR &= ~FLASH_CR_PG; return 0; //返回成功 } #endif //====================================================================== //函数名称:flash_Best //函数返回:0-成功 1-失败 //参数说明:sect:待写入扇区号 // offset:待写入数据位置的偏移地址 // N:待写入数据字节数 // buf:待写入数据的首地址 //功能概要:首位地址都对齐的情况下的数据写入 //编程参考:暂无 //====================================================================== uint8_t flash_Best(uint16_t sect,uint16_t offset,uint16_t N,uint8_t *buf) { //(1)定义变量。temp_l,temp_h,addr,i uint32_t temp_l,temp_h; uint32_t addr; uint16_t i; //(2)等待 FLASH_SR 寄存器中的 BSY 位清零,等待操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); //(3)计算双字写入绝对地址 addr = (uint32_t)(FLASH_BASE+sect*FLASH_PAGE_SIZE+offset); //(4)循环写入双字,每8个数写一次 for(i = 0; i < N; i+=8) { //(4.1)低位字赋值 temp_l = (uint32_t)((buf[i])|(buf[i+1]<<8)|(buf[i+2]<<16)|(buf[i+3]<<24)); //(4.2)高位字赋值 temp_h = (uint32_t)((buf[i+4])|(buf[i+5]<<8)|(buf[i+6]<<16)|(buf[i+7]<<24)); //(4.3)在绝对地址(addr+i),实现双字写入 flash_write_DoubleWord((addr+i),temp_l,temp_h); } //(5)等待 FLASH_SR 寄存器中的 BSY 位清零,等待操作完成 while( (FLASH->SR & FLASH_SR_BSY) != 0U); return 0; }

 

使用步骤:

  明确一点,我们从50号扇区开始写,避免把BIOS给覆盖了。

  写之前先擦一遍,把脏数据给清楚了 flash_erase()

  然后就可以写了flash_write(), flash_logic_read()

 

 

adc 和 dac 这里的a指的是Analogue模拟量d指的是Digital数字量

adc a -> d 模拟量转数字量, 根据公式把传感器捕捉环境所得到的电平转换为数字量

dac d -> a 数字量转模拟量, 根据公式,把数字量换算为电平

//======================================================================
//文件名称:adc.c
//框架提供:苏州大学恩智浦嵌入式中心(sumcu.suda.edu.cn)
//版本更新:2019-9-20 V1.1
//功能描述:见本工程的<01_Doc>文件夹下Readme.txt文件
//======================================================================
#include "includes.h"

//======================================================================
//函数名称:adc_init
//功能概要:初始化一个AD通道号与采集模式
//参数说明:Channel:通道号;可选范围:ADC_CHANNEL_VREFINT、
//         ADC_CHANNEL_TEMPSENSOR、ADC_CHANNEL_x(1=<x<=16)、ADC_CHANNEL_VBAT
//         diff:差分选择。=1(AD_DIFF 1),差分;=0(AD_SINGLE);
//         单端;ADC_CHANNEL_VREFINT、ADC_CHANNEL_TEMPSENSOR、ADC_CHANNEL_VBAT
//         强制为单端;ADC_CHANNEL_x(1=<x<=16)可选单端或者差分模式
//======================================================================

void adc_init(uint16_t Channel,uint8_t Diff)
{
    //(1)开启ADC时钟,频率=总线时钟/4,48MHz,ADC时钟不超过14MHz
    RCC->AHB2ENR |= RCC_AHB2ENR_ADCEN;
    ADC1_COMMON->CCR |= ADC_CCR_CKMODE; //4分频

    //(2)退出掉电状态并使能稳压器,ADC默认处于掉电状态以降低功耗
    //【20220614修改】
    if(Diff == AD_DIFF)
    {
        ADC1->CR |= (1<<30);       //在差分输入模式下启动校准
    }else
    {
        ADC1->CR &= ~(1<<30);      //在单端输入模式下启动校准
    }
    ADC1->CR &= ~ADC_CR_DEEPPWD;
    ADC1->CR |= 1<<31;             //开始校准
    ADC1->CR |= ADC_CR_ADVREGEN;   
    for(volatile uint32_t i = 0;i<48000;i++) //延时1毫秒以稳定
    //(3)使能ADC相关内部采集功能
    if(Channel == 0)
    {
        ADC1_COMMON->CCR |= ADC_CCR_VREFEN;  //使能参考电压采集功能
    }
    else if(Channel == 17)
    {
        ADC1_COMMON->CCR |= ADC_CCR_TSEN;    //使能温度采集功能
    }
    else if(Channel == 18)
    {
        ADC1_COMMON->CCR |= ADC_CCR_VBATEN;  //使能基准电压采集功能
    }
    
    //(4)初始化ADC控制寄存器,清零各个控制位
    ADC1->CR &= 0x3fffffc0;
    //(5)单端差分选择
    if (Diff)
    {
        BSET(Channel,ADC1->DIFSEL);  
    }
    else
    {
        BCLR(Channel,ADC1->DIFSEL);    
    }
    
    //(6)开启ADC
    ADC1->CR |= ADC_CR_ADEN;
    
    //(7)设置采样时间为12.5个时钟周期
    if((int)Channel >= 0 && (int)Channel <= 9 )
    {
        BCLR(Channel*3,ADC1->SMPR1);
        BSET(Channel*3+1,ADC1->SMPR1);
        BCLR(Channel*3+2,ADC1->SMPR1);
    }
    if((int)Channel >= 10 && (int)Channel <= 18 )
    {
        BCLR((Channel%10)*3,ADC1->SMPR2);
        BSET((Channel%10)*3+1,ADC1->SMPR2);
        BCLR((Channel%10)*3+2,ADC1->SMPR2);
    }
    //(8)配置寄存器CFGR:精度12位、右对齐、单次单通道转换
    ADC1->CFGR &= 0xffffffe7;           //精度设置为12位
    ADC1->CFGR &= 0xffffffdf;           //数据对齐方式右对齐
    ADC1->CFGR |= ADC_CFGR_DISCEN;      //不连续转换模式
    ADC1->CFGR &= ~ADC_CFGR_CONT;       //单次转换模式
    ADC1->CFGR &= ~ADC_CFGR_DISCNUM;    //一个通道
    ADC1->CFGR &= ~ADC_CFGR_EXTEN;      //禁止硬件触发检测
    //(9)常规通道序列长度为1
    ADC1->SQR1 &= ~ADC_SQR1_L;       
}

//============================================================================
//函数名称:adc_read
//功能概要:初始化一个AD通道与引脚采集模式
//参数说明:diff:差分选择。=1(AD_DIFF 1),差分;=0(AD_SINGLE);
//         单端;DC_CHANNEL_VREFINT、ADC_CHANNEL_TEMPSENSOR、ADC_CHANNEL_VBAT
//         强制为单端;ADC_CHANNEL_x(1=<x<=16)可选单端或者差分模式
//============================================================================
uint16_t adc_read(uint8_t Channel)
{
    uint16_t ADCResult;   //用于存放AD值
    volatile int i,t;
    ADCResult=0;
    //(1)开启ADC,使能稳压器
    ADC1->CR |= ADC_CR_ADEN;
    ADC1->CR |= ADC_CR_ADVREGEN;
    for (i=0;i<=150;i++) __asm("nop");
    //(2)清空第一次转换序列
    ADC1->SQR1 &= 0xFFFFF83F; 
    //(3)所选通道加入第一次转换序列中
    ADC1->SQR1 |=((uint32_t)Channel<<6);
    //(4)开始转换
    ADC1->CR |= ADC_CR_ADSTART;
    //(5)等待转换完成,获取转换结果
    for (t = 0; t < 0xFBBB; t++)//查询指定次数
    {
        for (i=0;i<=20;i++) __asm("nop");
        //判断转换是否完成
        if (BGET(2,ADC1->ISR)==1)  //转换完成
        {
            ADCResult = ADC1->DR;   //读取数据,清转换完成标志位
            break;
        }
    } 
    return ADCResult;
}


//======================================================================
//函 数 名:adc_mid                                                  
//功    能:获取通道channel中值滤波后的A/D转换结果                    
//参    数:channel = 通道号                                           
//返    回:该通道中值滤波后的A/D转换结果                         
//内部调用:adc_read                                               
//======================================================================
uint16_t adc_mid(uint16_t Channel)
{
    uint16_t a,b,c;
    volatile uint32_t i;
    //1.取三次A/D转换结果
    a = adc_read(Channel);
    for (i=0;i<1500;i++) __asm("nop");
    b = adc_read(Channel);
    for (i=0;i<1500;i++) __asm("nop");
    c = adc_read(Channel);
   // 2.从三次A/D转换结果中取中值
    return  a > b ? (b > c ? b : ( a > c ? c : a)) : ( a > c ? a: (b > c ? c : a));
}

//======================================================================
//函 数 名:adc_ave                                                    
//功    能:1路A/D转换函数(均值滤波),通道channel进行n次中值滤波,求和再作  
//          均值,得出均值滤波结果                                        
//参    数:channel = 通道号,n = 中值滤波次数                               
//返    回:该通道均值滤波后的A/D转换结果                                   
//内部调用:adc_mid                                                          
//======================================================================
uint16_t adc_ave(uint16_t Channel,uint8_t n) 
{
    uint16_t i;
    uint32_t j;
    j = 0;
    for (i = 0; i < n; i++) j += adc_mid(Channel);
    j = j/n;
    return (uint16_t)j;
}


//============================================================================
//函数名称:adc_mcu_temp
//功能概要:将读到的芯片内部mcu温度AD值转换为实际温度
//参数说明:mcu_temp_AD:通过adc_read函数得到的AD值
//函数返回:实际温度值
//============================================================================
float adc_mcu_temp(uint16_t mcu_temp_AD)
{
    float mcu_temp_result;
    mcu_temp_result=(float)(6+55+(100*((float)(mcu_temp_AD) - AD_CAL1))/(AD_CAL2 - AD_CAL1));
    return mcu_temp_result;
 
}

 

 

//======================================================================
//文件名称:dac.c
//框架提供:苏州大学恩智浦嵌入式中心(sumcu.suda.edu.cn)
//版本更新:2020-12-4 V1.1
//功能描述:见本工程的<01_Doc>文件夹下Readme.txt文件
//======================================================================
#include "dac.h"
//======================================================================
//函数名称:dac_init
//功能概要:初始化DAC模块设定
//参数说明:port_pin:可选择DAC_PIN1代表通道1
//                    选择DAC_PIN2代表通道2
//======================================================================
void dac_init(uint16_t port_pin)
{
        //(1)开启DAC1时钟
        RCC->APB1ENR1 |= RCC_APB1ENR1_DAC1EN;
        //(2)选择使用DAC1的通道1或者通道2
        if(port_pin==1)
        {
            //DAC1通道1不使用触发功能,不生成波
            DAC1->CR &= ~DAC_CR_TEN1; //不使用触发功能
            DAC1->CR &= ~DAC_CR_WAVE1_0; //不生成波
            //DAC1通道1输出缓存关闭
            DAC1->MCR|=DAC_MCR_MODE1_2;
            //DAC1通道1软件触发
            DAC1->SWTRIGR|= DAC_SWTRIGR_SWTRIG1;
            //DAC1通道1启动
            DAC1->CR|=DAC_CR_EN1;
        }
        else if(port_pin==2)
        {
            //DAC1通道2不使用触发功能,不生成波
            DAC1->CR &= ~DAC_CR_TEN2; //不使用触发功能
            DAC1->CR &= ~DAC_CR_WAVE2_0; //不生成波
            //DAC1通道2输出缓存关闭
            DAC1->MCR|=DAC_MCR_MODE2_2;
            //DAC1通道2软件触发
            DAC1->SWTRIGR|= DAC_SWTRIGR_SWTRIG2;
            //DAC1通道2启动
            DAC1->CR|=DAC_CR_EN2;
        }

}
//============================================================================
//函数名称:dac_convert
//功能概要:执行DAC转换
//参数说明:port_pin:可选择DAC_PIN1代表通道1
//                   选择DAC_PIN2代表通道2
//          data:需要转换成数字量的模拟量:范围(0~4095)
//============================================================================
void dac_convert(uint16_t port_pin,uint16_t data)
{
    //(1)开启DAC1
    if(port_pin==1)
    {
        //开启DAC1通道1
        DAC1->CR|=DAC_CR_EN1;
        //通道1传递输入数值
           DAC1->DHR12R1 = data;
    }
    else if(port_pin==2)
    {
        //开启DAC1通道2
        DAC1->CR|=DAC_CR_EN2;
        //通道1传递输入数值
           DAC1->DHR12R2 = data;
    }
    
}

 

posted @ 2023-11-26 18:56  深渊之巅  阅读(59)  评论(0编辑  收藏  举报