一、简介
现象:本实验在使用ADC+DMA+EEPOM实验室,在eeprom写入数据的时候单片机死机,我在写eerpom时关闭adc和关闭dma,写完之后开启adc和dma单片机就不死机了,然后就出现adc数据错位的问题,经过一天的修改实验,现已没有死机和数据错位现象。本实验采用iar平台所做,参考手册为RM0031手册,采用寄存器方式。
二、stm8L的adc和dma寄存器:
1、时钟寄存器-adc和dma
相关代码:
CLK_PCKENR2_PCKEN20 = 1; /* 开启adc时钟 */
CLK_PCKENR2_PCKEN24 = 1; /* 开启DMA时钟 */
2、adc其他相关寄存器
相关代码:
ADC1_CR1_ADON = 1; /* 使能adc ADCON wake up from power down mode */
ADC1_CR1_CONT = 1; /* 0:单次转换 1:连续转换 */
ADC1_CR1_EOCIE = 0; /* 关闭adc中断 */
相关代码:
ADC1_CR2_PRESC = 0; /* select a sample time of 10 us f(ADC_CLK)=CK */
ADC1_CR2_SMTP1 = 0x06; /* 外部0-23通道采样时间24 */
相关代码:
ADC1_CR3_SMTP2 = 0x06; /* 内部参考电压通道采样时间为24 */
相关代码:(我这里使用通道7、8 、9)
/* 选择ADC通道 */
ADC1_SQR4_CHSEL_S7 = 1; //打开adc通道7
ADC1_TRIGR4_TRIG7 = 1; //关闭通道7的施密特触发器
ADC1_SQR3_CHSEL_S8 = 1; //选择通道8
ADC1_TRIGR3_TRIG8 = 1; //关闭通道8的施密特触发器
ADC1_SQR3_CHSEL_S9 = 1; //选择通道9
ADC1_TRIGR3_TRIG9 = 1; //关闭通道9的施密特触发器
相关代码:
ADC1_SQR1_DMAOFF = 0; /* 使能DMA */
3、dma相关寄存器
相关代码:
SYSCFG_RMPCR1_ADC1DMA_REMAP = 1; /* 设置DMA通道 */
相关代码:
DMA1_C1CR_CIRC = 1; /* 设置模式 */
DMA1_C1CR_MINCDEC = 1; /* 设置增还是减去地址 */
DMA1_C1CR_TCIE = 1; /* 使能传送完一组数据中断 */
DMA1_C1CR_EN = 1; /* 使能DMA1通道 */
相关代码:
DMA1_C1SPR_PL0 = 0; /* 设置通道优先级 */
DMA1_C1SPR_PL1 = 1;
DMA1_C1SPR_TSIZE = 1; /* 设置传送位数 */
相关代码:
DMA1_C1NDTR = 12; /* 设置传送字节 */
相关代码:
DMA1_GCSR_GEN = 1; /* DMA全局使能 */
三、部分实验代码:
1、adc配置
void ADC_Init(void)
{
CLK_PCKENR2_PCKEN20 = 1; /* 开启adc时钟 */
ADC1_CR1_ADON = 1; /* 使能adc ADCON wake up from power down mode */
ADC1_CR1_CONT = 1; /* 0:单次转换 1:连续转换 */
ADC1_CR2_PRESC = 0; /* select a sample time of 10 us f(ADC_CLK)=CK */
// 0: f(ADC_CLK) = CK
// 1: f(ADC_CLK) = CK/2 //系统时钟此时为默认的16M/8=2M,这里分频后,fadc=2M/2=1M
//ADC1_SQR1_DMAOFF = 1; /* 关闭DMA */
ADC1_SQR1_DMAOFF = 0; /* 使能DMA */
ADC1_CR3_SMTP2 = 0x06; /* 内部参考电压通道采样时间为24 */
//000: 4 ADC clock cycles
//001: 9 ADC clock cycles
//010: 16 ADC clock cycles
//011: 24 ADC clock cycles
//100: 48 ADC clock cycles
//101: 96 ADC clock cycles
//110: 192 ADC clock cycles
//111: 384 ADC clock cycles
ADC1_CR2_SMTP1 = 0x06; /* 外部0-23通道采样时间24 */
/* 选择ADC通道 */
ADC1_SQR4_CHSEL_S7 = 1; //打开adc通道7
ADC1_TRIGR4_TRIG7 = 1; //关闭通道7的施密特触发器
ADC1_SQR3_CHSEL_S8 = 1; //选择通道8
ADC1_TRIGR3_TRIG8 = 1; //关闭通道8的施密特触发器
ADC1_SQR3_CHSEL_S9 = 1; //选择通道9
ADC1_TRIGR3_TRIG9 = 1; //关闭通道9的施密特触发器
//ADC1_CR1_EOCIE = 1; /* 开启adc中断 */
}
2、dma初始化
void ADC1_DMA_Init(void)
{
/* 开启DMA时钟 */
CLK_PCKENR2_PCKEN24 = 1;
/* 设置DMA通道 */
SYSCFG_RMPCR1_ADC1DMA_REMAP = 1;
/* 设置传送字节 */
DMA1_C1NDTR = 12;
/* 设置通道优先级 */
DMA1_C1SPR_PL0 = 0;
DMA1_C1SPR_PL1 = 1;
/* 设置传送方向 */
DMA1_C1CR_DIR = 0;
/* 设置模式 */
DMA1_C1CR_CIRC = 1;
/* 设置增还是减去地址 */
DMA1_C1CR_MINCDEC = 1;
/* 设置传送位数 */
DMA1_C1SPR_TSIZE = 1;
/* 使能传送完一组数据中断 */
//DMA1_C1CR_HTIE = 1;
DMA1_C1CR_TCIE = 1;
/* 设置DMA通道1外设地址 */
DMA1_C1PARH=(uint8_t)((uint16_t)ADC_DRH_ADRESS >> (uint8_t)8);
DMA1_C1PARL=(uint8_t)ADC_DRH_ADRESS;
/* 设置DMA通道1内存地址 */
DMA1_C1M0ARH=(uint8_t)((uint16_t)&adc_dmaval >> (uint8_t)8);
DMA1_C1M0ARL=(uint8_t)&adc_dmaval;
/* 使能DMA1通道 */
DMA1_C1CR_EN = 1;
/* DMA全局使能 */
DMA1_GCSR_GEN = 1;
}
3、中断函数
#pragma vector=DMA1_CH1_TC_vector
__interrupt void DMA1_CH1_TC_ISR(void)
{
if(DMA1_C1SPR_TCIF == 1)
{
DMA1_C1SPR_TCIF = 0;
/* 直接从变量中读取数据 */
}
}
4、暂时关闭adc
本实验采用关闭adc时钟的方式关闭adc,在写入eeprom数据前,关闭adc,在写入eeprom数据后开启adc时钟。
void ADC1_Close(void)
{
CLK_PCKENR2_PCKEN20 = 0; /* 开启adc时钟 */
}
5、开启adc
在写完eeprom数据后,开启adc时钟。
void ADC1_ReStart(void)
{
CLK_PCKENR2_PCKEN20 = 1; /* 开启adc时钟 */
}