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; } }