Define a variable on the OLED display and see that it starts with 0x2000 on the SRAM; add const before the variable to make it a constant and then check the address that starts with 0x8000 on the Flash, if there is a piece of data that does not need to be changed Large content can be stored in Flash to save SRAM space.
For peripheral registers, their addresses are fixed: first check the starting address of the peripheral where the register is located (Chapter 2 Memory Map), and then check the offset in the peripheral register table. The result is the start address + offset.
Define a peripheral structure. If the starting address of this structure is specified as the starting address of the ADC1 peripheral register, then the memory of the structure will be perfectly mapped to the memory of the peripheral register, so accessing a member variable of the structure is equivalent to accessing a certain register of this peripheral
ADC1->DR ADC1 is a structure pointer, which points to the start address of ADC1 peripherals. Accessing structure members is equivalent to adding an offset, and the start address plus offset is the specified register.
DMA data transfer
#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 is a device of the AHB bus, so use AHB to open the clock function. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); \t DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_PeripheralBaseAddr=ADDRA; DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; //Peripheral self-increment DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable; DMA_InitStruct.DMA_MemoryBaseAddr=ADDRB; DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //Memory auto-increment DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable; DMA_InitStruct.DMA_BufferSize=size; DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC; //software trigger DMA_InitStruct.DMA_M2M=DMA_M2M_Enable; DMA_InitStruct.DMA_Mode=DMA_Mode_Normal; DMA_InitStruct.DMA_Priority=DMA_Priority_Medium; \t DMA_Init(DMA1_Channel1, & DMA_InitStruct); DMA_Cmd(DMA1_Channel1, ENABLE); DMA_Cmd(DMA1_Channel1, DISABLE); } //The above code is transferred immediately after initialization, and the DMA stops after one transfer. //Call this function once to start a DMA transfer void MyDMA_Transfer(void) { //Set the transmission counter value, first disable and then enable DMA_Cmd(DMA1_Channel1, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size); DMA_Cmd(DMA1_Channel1, ENABLE); //Wait for transfer to complete while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET); //clear flag DMA_ClearFlag(DMA1_FLAG_TC1); \t }
main function
uint8_t DataA[]={0x01,0x02,0x03,0x04}; uint8_t DataB[]={0,0,0,0}; int main(void) { OLED_Init(); \t MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4); OLED_ShowString(1,1,"DataA"); OLED_ShowString(3,1,"DataB"); \t 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); \t\t Delay_ms(1000); //In the while, manually call the transfer, call the transfer once MyDMA_Transfer(); \t\t 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); \t\t } }
DMA + AD multi-channel
What is commented out is the one-shot mode
#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); \t RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //12MHZ \t GPIO_InitTypeDef GPIO_Init_Structure; //Configure as analog input mode 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); \t 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; //Single mode ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //Continuous mode whether to scan continuously 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; //four positions ADC_Init(ADC1, & ADC_InitStruct); \t DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t) & amp;ADC1->DR; //4001244C DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //Low 16-bit ADC1, high 16ADC2 DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;// Whether the peripheral is self-increasing 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; //Do not use software trigger // DMA_InitStruct.DMA_Mode=DMA_Mode_Normal; DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;//circular mode: transfer counter is automatically reloaded DMA_InitStruct.DMA_Priority=DMA_Priority_Medium; //The hardware trigger of ADC1 is only connected to channel 1 of DMA, see the DMA request map DMA_Init(DMA1_Channel1, & DMA_InitStruct); \t DMA_Cmd(DMA1_Channel1, ENABLE); \t //Enable the output from ADC to DMA, that is, the peripheral request signal in the DMA request image diagram ADC_DMACmd(ADC1, ENABLE); //Enable it ADC_Cmd(ADC1, ENABLE); \t //reset calibration ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET); //This bit is set by software and cleared by hardware. This bit will be cleared after the calibration register is initialized ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) == SET); \t ADC_SoftwareStartConvCmd(ADC1,ENABLE);//Continuous mode: put the ADC trigger directly in the last line of initialization, AD_GetValue does not need } /** * @brief ADC starts to convert, scans 4 channels continuously, and DMA also transfers synchronously * @param * @retval */ //void AD_GetValue(void) //{ // //Single-shot mode requires software to trigger ADC to start ADC_SoftwareStartConvCmd(ADC1,ENABLE); // // DMA_Cmd(DMA1_Channel1,DISABLE); // DMA_SetCurrDataCounter(DMA1_Channel1,4); // DMA_Cmd(DMA1_Channel1, ENABLE); // //transport after conversion // while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET); // DMA_ClearFlag(DMA1_FLAG_TC1); //}
The main function displays the sensor changes
int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"AD0:");//Potentiometer OLED_ShowString(2,1,"AD1:");//Infrared sensor OLED_ShowString(3,1,"AD2:");//Temperature sensing OLED_ShowString(4,1,"AD3:");//through-beam infrared sensor while(1) { \t\t 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); \t\t Delay_ms(1000); } }