定义一个变量在OLED显示屏上看到是0x2000开头的说明早SRAM上;在变量前加上const使其变成常量再查看地址以0x8000开头说明在Flash上,如果有一块不需要更改的数据较大的内容可以将它存储在Flash中以节省SRAM空间。
对于外设寄存器它们的地址是固定的:先查寄存器所在外设的起始地址(第二章存储器映像),然后在外设的寄存器总表查偏移。结果是起始地址+偏移。
定义一个外设结构体。如果指定这个结构体起始地址就是ADC1外设寄存器起始地址,那么结构体内存就会和外设寄存器内存完美映射,所以访问结构体某个成员变量相当于访问这个外设的某个寄存器
ADC1->DR ADC1是结构体指针,指向的是ADC1外设的起始地址,访问结构体成员就相当于加一个偏移,起始地址加偏移就是指定的寄存器。
DMA数据转运
#include "stm32f10x.h" // Device header
uint16_t MyDMA_Size;
void MyDMA_Init(uint32_t ADDRA,uint32_t ADDRB,uint16_t size)
{
MyDMA_Size=size;
//DMA是AHB总线的设备,所以要用AHB开启时钟的函数。
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr=ADDRA;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
//外设自增
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;
DMA_InitStruct.DMA_MemoryBaseAddr=ADDRB;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
//存储器自增
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_BufferSize=size;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
//软件触发
DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;
DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
DMA_Init(DMA1_Channel1,&DMA_InitStruct);
DMA_Cmd(DMA1_Channel1,ENABLE);
DMA_Cmd(DMA1_Channel1,DISABLE);
}
//上述代码是初始化后立刻转运,转运一次DMA就停止,
//调用一次这个函数就启动一次DMA转运
void MyDMA_Transfer(void)
{
//设置传输计数器值,先失能再使能
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
DMA_Cmd(DMA1_Channel1,ENABLE);
//等待转运完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
//清除标志位
DMA_ClearFlag(DMA1_FLAG_TC1);
}
主函数
uint8_t DataA[]={0x01,0x02,0x03,0x04};
uint8_t DataB[]={0,0,0,0};
int main(void)
{
OLED_Init();
MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);
OLED_ShowString(1,1,"DataA");
OLED_ShowString(3,1,"DataB");
OLED_ShowHexNum(1,8,(uint32_t)DataA,8);
OLED_ShowHexNum(3,8,(uint32_t)DataB,8);
while(1)
{
DataA[0]++;
DataA[1]++;
DataA[2]++;
DataA[3]++;
OLED_ShowHexNum(2,1,DataA[0],2);
OLED_ShowHexNum(2,4,DataA[1],2);
OLED_ShowHexNum(2,7,DataA[2],2);
OLED_ShowHexNum(2,10,DataA[3],2);
OLED_ShowHexNum(4,1,DataB[0],2);
OLED_ShowHexNum(4,4,DataB[1],2);
OLED_ShowHexNum(4,7,DataB[2],2);
OLED_ShowHexNum(4,10,DataB[3],2);
Delay_ms(1000);
//在while里,手动调用转运,调用一次转运一次
MyDMA_Transfer();
OLED_ShowHexNum(2,1,DataA[0],2);
OLED_ShowHexNum(2,4,DataA[1],2);
OLED_ShowHexNum(2,7,DataA[2],2);
OLED_ShowHexNum(2,10,DataA[3],2);
OLED_ShowHexNum(4,1,DataB[0],2);
OLED_ShowHexNum(4,4,DataB[1],2);
OLED_ShowHexNum(4,7,DataB[2],2);
OLED_ShowHexNum(4,10,DataB[3],2);
}
}
DMA+AD多通道
被注释掉的是单次模式
#include "stm32f10x.h" // Device header
uint16_t AD_Value[4];
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //12MHZ
GPIO_InitTypeDef GPIO_Init_Structure;
//配置为模拟输入模式
GPIO_Init_Structure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_Init_Structure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init_Structure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Init_Structure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); //55.5+12.5=68
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); //55.5+12.5=68
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); //55.5+12.5=68
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5); //55.5+12.5=68
ADC_InitTypeDef ADC_InitStruct;
// ADC_InitStruct.ADC_ContinuousConvMode=DISABLE; //单次模式
ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续模式 是否连续扫描
ADC_InitStruct.ADC_ScanConvMode=ENABLE;
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel=4; //四个位置
ADC_Init(ADC1,&ADC_InitStruct);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR; //4001244C
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //低16位ADC1,高16ADC2
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设是否自增
DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)AD_Value;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//
DMA_InitStruct.DMA_BufferSize=4;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_M2M=DMA_M2M_Disable; //不使用软件触发
// DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;//循环模式:传输计数器自动重装
DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
//ADC1的硬件触发只接在了DMA的通道1,看DMA请求映像图
DMA_Init(DMA1_Channel1,&DMA_InitStruct);
DMA_Cmd(DMA1_Channel1,ENABLE);
//开启ADC到DMA的输出,也就是DMA请求映像图中外设请求信号
ADC_DMACmd(ADC1,ENABLE);
//使能啦
ADC_Cmd(ADC1,ENABLE);
//复位校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET); //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//连续模式:把ADC触发直接放在初始化的最后一行,AD_GetValue不需要
}
/**
* @brief ADC开始转换,连续扫描4个通道,DMA也同步进行转运
* @param
* @retval
*/
//void AD_GetValue(void)
//{
// //单次模式 需要软件触发ADC开始
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
//
// DMA_Cmd(DMA1_Channel1,DISABLE);
// DMA_SetCurrDataCounter(DMA1_Channel1,4);
// DMA_Cmd(DMA1_Channel1,ENABLE);
// //转运在转换之后
// while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
// DMA_ClearFlag(DMA1_FLAG_TC1);
//}
主函数显示传感器的变化
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"AD0:");//电位器
OLED_ShowString(2,1,"AD1:");//红外传感
OLED_ShowString(3,1,"AD2:");//温度传感
OLED_ShowString(4,1,"AD3:");//对射式红外传感
while(1)
{
OLED_ShowNum(1,5,AD_Value[0],4);
OLED_ShowNum(2,5,AD_Value[1],4);
OLED_ShowNum(3,5,AD_Value[2],4);
OLED_ShowNum(4,5,AD_Value[3],4);
Delay_ms(1000);
}
}