2022-02-24 STM32F103 双重 ADC 同步规则模式采集实验

STM32 0.96 与 0.91 OLED 的屏幕使用

双重 ADC 同步规则模式采集实验与多路LCD 波形示波器制作显示,本文展示了STM32 AD 双重 ADC 同步规则模式采集实验。


STM32 AD 采集往期回顾

1 STM32F103 AD多通道DMA采集 独立模式与多路LCD 波形示波器制作显示 以及蓝牙传输串口数据
2 STM32F103 AD独立模式单通道采集 与LCD触摸 波形显示

代码:


在这里插入图片描述

内容涉及 :

  1. STM32 AD 双重 ADC 同步规则
  2. AD多通道DMA采集与存储调用
  3. AD采样点的构造体封装
  4. AD 的处理以及 LCD波形输出 模仿示波器的原理
  5. LCD触摸画板的控制
  6. SRAM 内存扩展管理
  7. FatFs 文件系统移植
  8. SPI函数移植过程
  9. SPI字节数据模拟输出独写 缓存读写
  10. USART串口的识别
  11. IO口输入输出
  12. 按键的外部中断处理
  13. 32位数据通讯,字符串通讯,单字符通讯

一:编程要点

  1. 初始 ADC 用到的 GPIO;
  2. 初始化 ADC GPIO;
  3. 初始化 DMA 配置;
  4. 初始化 ADC 参数;
  5. 读取 ADC
  6. 采集的数据,并打印出来校正;
  7. 设置 ADC 的工作参数并初始化;
  8. 设置 ADC 工作时钟;
  9. 设置 ADC 转换通道顺序及采样时间;
  10. 配置DMA 工作参数;
  11. 使能 ADC 7) 读取 ADC 采集的数据。
同步规则模式是 ADC1 和 ADC2 同时转换一个规则通道组,ADC1 是主,ADC2 是从。
ADC1 转换的结果放在 ADC1_DR 的低 16位,ADC2 转换的结果放在 ADC1_DR 的高十六位。
并且必须开启 DMA 功能。外部触发来自 ADC1 的规则组多路开关(由 ADC1_CR2 寄存器的 EXTSEL[2:0]选择)。
它同时给 ADC2 提供同步触发。为了简单起见,ADC1 我们选择软件触发,ADC2 必须选择外部触发。
这个外部触发来自于 ADC1 的规则组多路开关。

二:ADC 的工作具体如下

<font color=#FF00000> 

AD转换包括采样阶段和转换阶段,在采样阶段才对通道数据进行采集;
而在转换阶段只是将采集到的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。
独立模式的 ADC 采集需要在一个通道采集并且转换完成后才会进行下一个通道的采集。
而双重 ADC 的机制就是使用两个 ADC 同时采样一个或者多个通道。
双重 ADC 模式较独立模式一个最大的优势就是提高了采样率,弥补了单个 ADC 采样不够快的缺点。
启用双 ADC模式的时候,通过配置 ADC_CR1寄存器的 DUALMOD[3:0]位,可以有几种不同的模式,具体见表格 31-1

在这里插入图片描述

三:代码分析

1:ADC_book.h

代码如下:

#ifndef      __ADC_BOOK_H
#define	     __ADC_BOOK_H
#include "stm32f10x.h"

// ADC GPIO宏定义
// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define    ADC_GPIO_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define    ADC_GPIO_CLK                  RCC_APB2Periph_GPIOC  
#define    ADC_PORT                      GPIOC

// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define   ADC_APBxClock_FUN             RCC_APB2PeriphClockCmd
#define   ADC_X                         ADC1 //ADC2
#define   ADC_Y                         ADC2 //ADC2
#define   ADC_CLKX                      RCC_APB2Periph_ADC1
#define   ADC_CLKY                      RCC_APB2Periph_ADC2

//-------------------------------- ADC DMA 配置 ------------------------         
 // ADC1 对应 DMA1 通道 1,ADC3 对应 DMA2 通道 5,ADC2 没有 DMA 功能
#define 	ADC_DMA_CLK  									  RCC_AHBPeriph_DMA1
#define 	ADC_DMA_CHANEL 									DMA1_Channel1
#endif    

//ADC   中断相关宏定义
#define    ADC_IRQ                       ADC1_2_IRQn
#define    ADC_IRQHandler                ADC1_2_IRQHandler

//-------------------------------- ADC配置 ------------------------------
 
// 双通道ADC同步设计
#define  	 __ADC_RegSimult_Mode__ 						//使能标志位
#ifdef    __ADC_RegSimult_Mode__ 
#define    NOFCHANEL										 2  //转换通道的个数
#define    _DMA_BufferSize               1 
  	#define    ADC_PIN1                      GPIO_Pin_1
	#define    ADC_CHANNEL1                  ADC_Channel_11
	#define    ADC_PIN4                      GPIO_Pin_4
	#define    ADC_CHANNEL4                  ADC_Channel_14

#endif 
 
typedef union {
  struct{
    unsigned char BIT0:1;unsigned char BIT1:1;unsigned char BIT2:1;unsigned char BIT3:1;
    unsigned char BIT4:1;unsigned char BIT5:1;unsigned char BIT6:1;unsigned char BIT7:1;
    //unsigned char BIT8:1;unsigned char BIT9:1;unsigned char BIT10:1;unsigned char BIT11:1;
    //unsigned char BIT12:1;unsigned char BIT13:1;unsigned char BIT14:1;unsigned char BIT15:1;
  }DATA_BIT;
  uint8_t DATA_BYTE;
}Per_adc_type;

extern volatile  Per_adc_type  adc_flag;
  #define badc_10ms         adc_flag.DATA_BIT.BIT0
 
extern volatile  uint32_t   Count_Adc_flag;


//----------- 双通道ADC同步设计-------	
#ifdef  	 __ADC_RegSimult_Mode__
	extern volatile  uint32_t   ADC_RegSimult_ConvertedValue[NOFCHANEL];
	extern volatile  float 			ADC_RegSimult_ConvertedValueLocal[NOFCHANEL];
#endif

void ADCx_Init(void);
void ADC_get_value(void);

#endif 

2:ADC_book.c

使用到 GPIO 时候都必须开启对应的 GPIO 时钟,GPIO 用于 AD 转换功能必须配置为模拟输入模式。
ADCx_Mode_Config()与独立模式多通道配置基本一样,只是有几点需要注意:
ADC 工作模式要设置为同步规则模式;两个 ADC 的通道的采样时间需要一致;
ADC1设置为软件触发;ADC2 设置为外部触发。其他的基本一样,看代码注释理解即可。

#include "ADC_book.h"
#include "XPT2046_LCD_GridDiagram_book.h"

volatile  Per_adc_type  adc_flag;		  
volatile  uint32_t 			Count_Adc_flag;

#ifdef  	 __ADC_RegSimult_Mode__ 
__IO 		uint32_t 		ADC_RegSimult_ConvertedValue[NOFCHANEL]={0,0};
__IO 		uint32_t 		ADC_RegSimult_ConvertedValue_Show[NOFCHANEL]={0,0};
__IO 		float 		  ADC_RegSimult_ConvertedValueLocal[NOFCHANEL];
#endif


/**
  * @brief  ADC GPIO 初始化函数
  * @param  无
  * @retval 无
  */
static void ADCx_GPIO_Config(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	// 打开ADC IO 端口时钟
	ADC_GPIO_APBxClock_FUN (ADC_GPIO_CLK , ENABLE); 
	//配置 ADC IO 端口的模式   
	//-----------双通道ADC同步设计-------------
	#ifdef  	 __ADC_RegSimult_Mode__
	GPIO_InitStructure.GPIO_Pin = ADC_PIN1|
	ADC_PIN4; 
	#endif 
 
	// 必须为模拟输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 
	//初始化 ADDC_IO
	GPIO_Init(ADC_PORT , &GPIO_InitStructure );
	
}
	
/**
  * @brief  配置ADC DMA 工作模式
  * @param  
  * @retval 
  */
static void ADCx_DMA_Config(void){
  DMA_InitTypeDef  DMA_InitStructure; 
  //打开DMA时钟
	RCC_AHBPeriphClockCmd(ADC_DMA_CLK , ENABLE);
	//复位DMA 控制器
  DMA_DeInit(ADC_DMA_CHANEL);
	//配置DMA初始化结构体
  // 外设基址为:ADC 数据寄存器地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_X->DR));
	
  // 存储器地址,实际上就是一个内部SRAM的变量
	#ifdef  	 __ADC_RegSimult_Mode__
	//----------- 双通道ADC同步设计-------	
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_RegSimult_ConvertedValue;
	#endif 
  // 数据源来自外设
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	// 缓冲区大小为1,缓冲区的大小应该等于存储器的大小 
  DMA_InitStructure.DMA_BufferSize = _DMA_BufferSize ;
	// 外设寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  
	#ifdef  	 __ADC_RegSimult_Mode__
	// 外设数据大小为半字,即两个字节
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
	// 存储器数据大小也为半字,跟外设数据大小相同
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;																							 
	#else
	// 外设数据大小为半字,即两个字节
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	// 存储器数据大小也为半字,跟外设数据大小相同
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	#endif

	// 循环传输模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	// 禁止存储器到存储器模式,因为是从外设到存储器
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	// 初始化DMA
	DMA_Init(ADC_DMA_CHANEL,&DMA_InitStructure);
	// 使能 DMA 通道
	DMA_Cmd(ADC_DMA_CHANEL , ENABLE);
}
	
/**
  * @brief  配置ADC 工作模式
  * @param  
  * @retval 
  */
static void ADCx_Mode_Config(void){
	ADC_InitTypeDef ADC_InitStructure;
  //----------- 双通道ADC同步设计-------	
  #ifdef  	 __ADC_RegSimult_Mode__
	//打开ADC时钟 
	ADC_APBxClock_FUN (ADC_CLKX , ENABLE);
	ADC_APBxClock_FUN (ADC_CLKY , ENABLE);
	#else
	ADC_APBxClock_FUN (ADC_CLKX , ENABLE);
  #endif 
  
	//--------ADC 模式配置  -----
	//----------- 双通道ADC同步设计-------	
  #ifdef  	 __ADC_RegSimult_Mode__
  // 双 ADC 的规则同步
  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
  // 扫描模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE; 
  #endif
    
	//连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	// 不用外部触发转换 ,软件开启即可 
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	//转换结果右侧对齐 
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  //----------- 双通道ADC同步设计-------	
  #ifdef  	 __ADC_RegSimult_Mode__
	ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL/2; 
  //初始化ADC 
	ADC_Init(ADC_X , &ADC_InitStructure);
  ADC_Init(ADC_Y , &ADC_InitStructure);
	#endif
  
	//配置ADC时钟为PCLCK2的8分频 为9HZ
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	//配置ADC转换通道转换顺序和采样时间
	
 
  //----------- 双通道ADC同步设计-------	
  #ifdef  	 __ADC_RegSimult_Mode__
	ADC_RegularChannelConfig(ADC_X , ADC_CHANNEL1 , 1 , ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC_Y , ADC_CHANNEL4 , 1 , ADC_SampleTime_239Cycles5);
	#endif
	//-----------AD通道采集------- 
  //-----------DMA模式----------
	#ifdef 	__ADC_DMA_Mode__   
		#ifdef  	 __ADC_RegSimult_Mode__
		// 只需要使能ADC1 DMA 请求
    //ADC1 我们选择软件触发,ADC2 必须选
		//择外部触发,这个外部触发来自于 ADC1 的规则组多路开关。
		ADC_DMACmd(ADC_X, ENABLE);
     /* 使能 ADCx_2 的外部触发转换 */
    ADC_ExternalTrigConvCmd(ADC_Y, ENABLE);
		#else
		// 使能ADC DMA 请求
		ADC_DMACmd(ADC_X, ENABLE);
		#endif 
	#else
	//ADC 转换结束产生中断,在中断服务程序中读取转换值
	ADC_ITConfig(ADC_X , ADC_IT_EOC , ENABLE);
	// 使能ADC DMA 请求
	ADC_DMACmd(ADC_X, ENABLE);
	#endif 
	//-----------DMA模式----------
  
	/* ----------------ADC 校准--------------------- */
  //----------- 双通道ADC同步设计-------	
  #ifdef  	 __ADC_RegSimult_Mode__
	//开启ADC 并开始转换
	ADC_Cmd(ADC_X , ENABLE);
	// 初始化ADC 校准寄存器 
	ADC_ResetCalibration(ADC_X);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADC_X));
	//ADC_采集校准 
	ADC_StartCalibration(ADC_X);
	//等待校准完成
	while(ADC_GetCalibrationStatus(ADC_X));
  

   //开启ADC 并开始转换
	ADC_Cmd(ADC_Y , ENABLE);
	// 初始化ADC 校准寄存器 
	ADC_ResetCalibration(ADC_Y);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADC_Y));
	//ADC_采集校准 
	ADC_StartCalibration(ADC_Y);
	//等待校准完成
	while(ADC_GetCalibrationStatus(ADC_Y));
   
	//由于没有采用外部触发 ,所以使用软件ADC转换
    //ADC 工作模式要设置为同步规则模式;两个 ADC 的通道的采样时间需要一致;
    //ADC1设置为软件触发;ADC2 设置为外部触发 
	ADC_SoftwareStartConvCmd(ADC_X , ENABLE);
  
	
}
 

static void ADC_NVIC_Config(void){
	NVIC_InitTypeDef  NVIC_InitStructure;
	//优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//配置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}


void ADC_IRQHandler(void){
	if( ADC_GetITStatus(ADC_X  , ADC_IT_EOC )==SET ){
		//读取ADC的转换值
		 //--------DMA模式-----
		#ifdef 	__ADC_DMA_Mode__ 
		#else
		ADC_ConvertedValue = ADC_GetConversionValue(ADC_X);		
		#endif 
	//--------DMA模式-----
		ADC_ClearITPendingBit(ADC_X , ADC_IT_EOC);
	}
  if( ADC_GetITStatus(ADC_Y  , ADC_IT_EOC )==SET ){
		//读取ADC的转换值
		 //--------DMA模式-----
		#ifdef 	__ADC_DMA_Mode__ 
		#else
		ADC_ConvertedValue = ADC_GetConversionValue(ADC_Y);		
		#endif 
	//--------DMA模式-----
	  ADC_ClearITPendingBit(ADC_Y , ADC_IT_EOC);	
	} 
  
}
 
/**********************END OF FILE**********************/

/**
  * @brief  ADC初始化
  * @param  无
  * @retval 无
  */
 void ADCx_Init(void){
	 //--------DMA模式-----
	#ifdef 	__ADC_DMA_Mode__ 
	ADCx_GPIO_Config();
  ADCx_DMA_Config();
	ADCx_Mode_Config();
	#else
	ADCx_GPIO_Config();
	ADCx_Mode_Config();
	ADC_NVIC_Config();  // DMA 模式不需要对中断进行处理	
	#endif 
	//--------DMA模式-----
	 
}


void ADC_get_value(void){
  uint16_t temp0=0 ,temp1=0;
  if(badc_10ms==0){return;}
  badc_10ms = 0;

  //-----------AD通道采集-------	
  #ifdef 		 __ADC_RegSimult_Mode__ 
	// 取出 ADC1 数据寄存器的高 16 位,这个是 ADC2 的转换数据
	temp0 = (ADC_RegSimult_ConvertedValue[0]&0XFFFF0000) >> 16;
	// 取出 ADC1 数据寄存器的低 16 位,这个是 ADC1 的转换数据
	temp1 = (ADC_RegSimult_ConvertedValue[0]&0XFFFF);
	printf("The current AD value %d = 0x%08X   \r\n",0,ADC_RegSimult_ConvertedValue[0]); 
  ADC_RegSimult_ConvertedValue_Show[0] = temp0 ;
  ADC_RegSimult_ConvertedValue_Show[1] = temp1  ;

	ADC_RegSimult_ConvertedValueLocal[0] = (float)temp0 /4096*3.3; 
	ADC_RegSimult_ConvertedValueLocal[1] = (float)temp1 /4096*3.3;
 		 
	printf("The current AD value %d = 0x%04X   %f V\r\n",0,ADC_RegSimult_ConvertedValue_Show[0],ADC_RegSimult_ConvertedValueLocal[0]); 
  printf("The current AD value %d = 0x%04X   %f V\r\n",1,ADC_RegSimult_ConvertedValue_Show[1],ADC_RegSimult_ConvertedValueLocal[1]); 
	printf("\r\n\r\n");
  GDScream_Data_show( ADC_RegSimult_ConvertedValue_Show,NOFCHANEL);
	#endif 
     
}

3:main.c

代码如下:

/*******************************************************************************
* @file    GPIO/JTAG_Remap/main.c 
* @author  MCD Application Team
* @version V3.5.0
* @date    08-April-2011
* @brief   Main program body
******************************************************************************
* @attention
*    
*    
******************************************************************************
*/ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "PROJ_book.h" 
 

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
void delay(int x);
void fn_LED_Flash_Init(void);
void fn_usart_show_Init(void);
void fn_DMA_show_Init(void);
void fn_I2C_EE_Init(void);
void fn_I2C_EE_Soft_Init(void);
void fn_SPI_FLASH_Soft_Init(void);
void fn_FatFs_Document_Init(void);
void fn_SRAM_Init(void);
void fn_LCD_Init(void);
void fn_XPT2046_Init(void);
void fn_Adc_Init(void);

#define countof(a)      (sizeof(a) / sizeof(*(a)))
  
#define  _I2C_BufferSize (countof(writeData)-1)
static uint8_t writeData[_I2C_PageSize]={4,5,6,7,8,9,10,11};
static uint8_t writeData2[_I2C_PageSize]={24,25,26,27,28,29,30,31};
static uint8_t ReadData[_I2C_BufferSize]={0};

#define  _SPI_BufferSize  SPI_PAGE_SIZE   //(countof(write_SPI_Data)-1)
static uint8_t write_SPI_Data[_SPI_BufferSize]={0};
static uint8_t Read_SPI_Data[_SPI_BufferSize]={0};

int main(void)
{  
      int16_t sAD_X, sAD_Y ;
      fn_Adc_Init(); 							//ADC 采集
      //*************LCD系统初始化**************  
      fn_XPT2046_Init(); 
      fn_Lcd_Page_Init();  
      fn_Lcd_Page4();
      while(1){     				 
	    ADC_get_value(); 	 
      }
}
 
//======================================================================
//======================================================================

void fn_LCD_Init(void){             //LCD运行测试
    __IO int16_t int_check;
    fn_Systick_Delay(500,_Systick_ms);
    int_check = (__IO int16_t)ILI9341_Init();
    Display_LCD_clear();
      switch(int_check){
        case 0x05:
            printf("\n-->LCD 运行正常\r\n");
            Lcd_display_String("  LCD 运行正常\r\n");     
            break;
        default:
            printf("\n-->LCD 运行异常\r\n");
            Lcd_display_String("   LCD 运行异常\r\n\r\n");
            
      }       
}

//======================================================================
//======================================================================

void fn_XPT2046_Init(void){             //XPT2046运行测试
   printf("\n-->LCD 触摸初始化\r\n");
   Lcd_display_String("  LCD 触摸初始化\r\n");   
   XPT2046_GPIO_Init();  
//   while(XPT2046_Touch_Calibrate_Page() == 0){;}
   Lcd_display_String("  LCD 触摸初始化ok\r\n");
}
//======================================================================
//======================================================================


void fn_Adc_Init(void){ 
		ADCx_Init();
}
 
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

4: XPT2046_LCD_GridDiagram_book.h

代码如下:

#ifndef      __XPT2046_LCD_GRIDDIAGRAM_BOOK__
#define	     __XPT2046_LCD_GRIDDIAGRAM_BOOK__

#include "stm32f10x.h"
															 
#include "XPT2046_LCD_Function_book.h"
#include "XPT2046_LCD_book.h"
#include "LCD_book.h"
#include "LCD_Draw_book.h" 
#include "XPT2046_LCD_Device_book.h"
#include "ADC_book.h"
#include "USART_book.h"

 
//======================================================形式是默认还是定制化=====================================================
/**

模式0:				.		模式1:		.	模式2:			.	模式3:					
					A		.					A		.		A					.		A									
					|		.					|		.		|					.		|							
					Y		.					X		.		Y					.		X					
					0		.					1		.		2					.		3					
	<--- X0 o		.	<----Y1	o		.		o 2X--->  .		o 3Y--->	
------------------------------------------------------------	
模式4:				.	模式5:			.	模式6:			.	模式7:					
	<--- X4 o		.	<--- Y5 o		.		o 6X--->  .		o 7Y--->	
					4		.					5		.		6					.		7	
					Y		.					X		.		Y					.		X						
					|		.					|		.		|					.		|							
					V		.					V		.		V					.		V		
---------------------------------------------------------				
											 LCD屏示例
								|---------|-----------------------------|
								|	AD测试	| 													  |
								|					|													    |
								|					|													    |
								|					|													    |
								|					|													    |
								|					|													    |
								|					|													    |
								|					|										    			|
								|					|										    			|
								|---------|-----------------------------|
								屏幕正面(宽240,高320)270 50 -2
**/
 
///******************************* XPT2046 触摸屏参数定义 ***************************/
 
 
#define	 XPT2046_GDCHANNEL_X 	       ILI9341_MORE_PIXEL 	          //通道Y+的选择控制字	
#define	 XPT2046_GDCHANNEL_Y 	       ILI9341_LESS_PIXEL	            //通道X+的选择控制字

#define  LCD_GDWork_X_LENGTH         270
#define  LCD_GDNwork_Y_LENGTH        238

#define  LCD_GDControl_X_Start       0
#define  LCD_GDControl_Y_Start       0
#define  LCD_GDControl_X_LENGTH      (XPT2046_GDCHANNEL_X - LCD_GDWork_X_LENGTH - 2)
#define  LCD_GDControl_Y_LENGTH      XPT2046_GDCHANNEL_Y

#define  LCD_GDSCAN_X_Start          (LCD_GDControl_X_LENGTH+1)
#define  LCD_GDSCAN_Y_Start          1
#define  LCD_GDSCAN_X_LENGTH         LCD_GDWork_X_LENGTH
#define  LCD_GDSCAN_Y_LENGTH         LCD_GDNwork_Y_LENGTH
#define  LCD_GDSCAN_X_End          	 (XPT2046_GDCHANNEL_X-1)
#define  LCD_GDSCAN_Y_End          	 (XPT2046_GDCHANNEL_Y-1)
#define  Center_lineNum 						 6

#define GDBUTTON_NUM     3


typedef struct{
	int16_t value_x_before ; 
	int16_t value_x_now ;
	int16_t value_y_before ; 
	int16_t value_y_now ;
	uint32_t para_color;	
	uint16_t data_value; 
  void (*draw_point)(void *draw_pot);     //按键描绘函数
   
}AD_Point;

void GDScream_Data_show(int32_t *data_value , uint16_t data_num);

 

#endif

5: XPT2046_LCD_GridDiagram_book.c

代码如下:

 /**
  ******************************************************************************
  * @file    palette.c
  * @author  fire
  * @version V1.0
  * @date     
  * @brief   触摸画板应用函数
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

#include "XPT2046_LCD_GridDiagram_book.h"
#include <stdio.h> 
#include <string.h>

Touch_Button GDbutton[GDBUTTON_NUM];

static void GDTouch_Button_Init(void);
static void Draw_btn_GDcontrol_Button(void *btn); 
static void Btn_command_GDcontrol_Button(void);
static void GDControl_Text_Init(void);
static void GDScream_show_Init(void);
static void GDScream_Line_Init(void);
static void GDScream_Data_show_init(void);
static void Draw_point(void * draw_pot);
 /**
* @brief  Palette_Init 画板初始化
* @param  无
* @retval 无
*/
#define _LCD_GDSCAN_MODE   LCD_SCAN_MODE_3
void GridDiagram_Init(void){
	uint16_t datax , datay;
  ILI9341_GramScan(_LCD_GDSCAN_MODE);
  
  //初始化画板颜色
  LCD_SetBackColor(CL_GREY2);
  ILI9341_Clear(0,0,XPT2046_GDCHANNEL_X+1,XPT2046_GDCHANNEL_Y+1);
  
  
  LCD_SetColors(CL_YELLOW , CL_WHITE);

 
  ILI9341_DrawRectangle(1,1,LCD_GDControl_X_LENGTH-1,LCD_GDControl_Y_LENGTH-1,0,1);
	LCD_SetColors(CL_WHITE , CL_WHITE);	
					 
  ILI9341_DrawRectangle(LCD_GDControl_X_Start ,
                        LCD_GDControl_Y_Start ,                    
                        LCD_GDControl_X_LENGTH, 
                        LCD_GDControl_Y_LENGTH,0,1);
   
  LCD_SetColors(CL_BLACK , CL_WHITE);						 
  ILI9341_DrawRectangle(LCD_GDSCAN_X_Start,
                        LCD_GDSCAN_Y_Start,                    
                        LCD_GDSCAN_X_LENGTH, 
                        LCD_GDSCAN_Y_LENGTH,1,1);
  GDScream_Line_Init();
  GDScream_Data_show_init();
  //初始化按钮
  GDTouch_Button_Init();
  GDControl_Text_Init();
  //对属性物件进行刷新
  GDScream_show_Init();
  
}


/**
* @brief  GDTouch_Button_Init 画板初始化
* @param  无
* @retval 无
*/
static void GDTouch_Button_Init(void){
	uint8_t i ;
	for(i = 0 ;i<=GDBUTTON_NUM ;i++ ){
    GDbutton[i].start_x = BUTTON_START_X+3; 
    GDbutton[i].end_x = GDbutton[i].start_x+COLOR_BLOCK_WIDTH ;
    GDbutton[i].start_y = (COLOR_BLOCK_HEIGHT + 20)*(i+1);
    GDbutton[i].end_y = GDbutton[i].start_y + COLOR_BLOCK_HEIGHT ;    
    GDbutton[i].touch_flag = 0;  
    GDbutton[i].draw_btn = Draw_btn_GDcontrol_Button ;
    GDbutton[i].btn_command = Btn_command_GDcontrol_Button ;
  }
  GDbutton[0].para = CL_GREY; //构建按钮的属性
	GDbutton[1].para = CL_GREY; //构建按钮的属性
	GDbutton[2].para = CL_GREY; //构建按钮的属性
	//描绘按钮
  for(i=0 ;i<GDBUTTON_NUM ;i++ ){
    GDbutton[i].draw_btn(&GDbutton[i]);
  }
}



/**
* @brief  Draw_btn_GDcontrol_Button 画板初始化
* @param  无
* @retval 无
*/
static void Draw_btn_GDcontrol_Button(void *btn){
	Touch_Button *ptr = (Touch_Button *)btn;
  //释放按键
  if( ptr->touch_flag == 0){
    //背景为功能键的颜色
    LCD_SetColors(ptr->para , CL_WHITE);
    ILI9341_DrawRectangle(ptr->start_x , ptr->start_y,\
                          ptr->end_x - ptr->start_x,\
												  ptr->end_y - ptr->start_y,1,1);
     
    //白色背景边框
    LCD_SetColors(CL_BOX_BORDER1 , CL_WHITE);
    ILI9341_DrawRectangle(ptr->start_x , ptr->start_y,\
                          ptr->end_x - ptr->start_x,\
												  ptr->end_y - ptr->start_y,0,2);
  }else{//按键按下
    //白色背景
    LCD_SetColors(CL_WHITE , CL_WHITE);
    ILI9341_DrawRectangle(ptr->start_x , ptr->start_y,\
                          ptr->end_x - ptr->start_x,\
												  ptr->end_y - ptr->start_y,1,1);
     //白色背景边框
    LCD_SetColors(CL_BOX_BORDER2 , CL_WHITE);
    ILI9341_DrawRectangle(ptr->start_x , ptr->start_y,\
                          ptr->end_x - ptr->start_x,\
												  ptr->end_y - ptr->start_y,0,2);
  }
}


/**
* @brief  Btn_command_GDcontrol_Button 画板初始化
* @param  无
* @retval 无
*/
static void Btn_command_GDcontrol_Button(void){
				 ;
}


/**
* @brief  Draw_btn_GDcontrol_Button 画板初始化
* @param  无
* @retval 无
*/
static void GDControl_Text_Init(void){
		LCD_SetColors(CL_RED,CL_WHITE);
	/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
	*中文字体大小是16*16的,需要其它字体请自行制作字模*/
	/*这个函数只对英文字体起作用*/
	LCD_SetFont(&Font8x16);
	ILI9341_DispString_EN_CH( LCD_GDControl_X_Start +2, LCD_GDControl_Y_Start + 5, "AD检查");

  	LCD_SetColors(CL_BLACK,CL_WHITE);
	/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
	*中文字体大小是16*16的,需要其它字体请自行制作字模*/
	/*这个函数只对英文字体起作用*/
	LCD_SetFont(&Font8x16);
	ILI9341_DispString_EN_CH( LCD_GDControl_X_Start +2, LCD_GDControl_Y_Start + 25, " 王琪");
}


/**
* @brief  Draw_btn_GDcontrol_Button 画板初始化
* @param  无
* @retval 无
*/


static void GDScream_Line_Init(void){
	uint8_t i ;	
	uint16_t center_linexstart , center_lineystart ,center_linexend , center_lineyend;
  uint16_t center_linespace  ;
	center_linexstart = LCD_GDSCAN_X_Start ;
	center_lineystart = XPT2046_GDCHANNEL_Y / 2;
	center_linexend   = LCD_GDSCAN_X_End;
	center_lineyend	= center_lineystart ;
  
  center_linespace = (XPT2046_GDCHANNEL_Y - 2 )/Center_lineNum ;
													 

  LCD_SetColors(CL_RED , CL_WHITE); 
  
  ILI9341_DrawLine( center_linexstart ,center_lineystart ,center_linexend ,center_lineyend,1 );
	LCD_SetColors(CL_YELLOW , CL_WHITE); 
	ILI9341_DrawLine( center_linexstart ,center_lineystart + center_linespace ,center_linexend ,center_lineyend + center_linespace,1 );
	ILI9341_DrawLine( center_linexstart ,center_lineystart - center_linespace ,center_linexend ,center_lineyend - center_linespace,1 );
	LCD_SetColors(CL_BLUE , CL_WHITE);
  ILI9341_DrawLine( center_linexstart ,center_lineystart + (center_linespace*2) ,center_linexend ,center_lineystart + (center_linespace*2),1 );
	ILI9341_DrawLine( center_linexstart ,center_lineystart - (center_linespace*2) ,center_linexend ,center_lineystart - (center_linespace*2),1 );
}

/**
* @brief  Draw_btn_GDcontrol_Button 画板初始化
* @param  无
* @retval 无
*/
static void GDScream_show_Init(void){
	uint8_t i ;	 
  for( i=0 ; i< (GDBUTTON_NUM); i++ ) {
		GDbutton[i].draw_btn(&GDbutton[i]);
	}
}

//===============================================关于屏幕画点的程序函数============================================== 

// 屏幕正面(宽320,高240) 

//   270 个像素
//   238 / 6  38   
//   500MS  一个数字  
//   像素间隔 Dx = 2 = 135 个数字
//   可以测试85S 的数据
//   4096 12 AD   每个像素高度为 20 *38 = 760  大约 0.6V  精度为0.02V   
//   设定变量 :uint16 data_value /  DX = 2  DY =  1 HX= 1 HY = 20 , uint16 data_value_before   data_value_now  ,    
	
#define   DX   1 
#define   DY   1 
#define   HX   1 
#define   HY   20
  
__IO int16_t data_value_x_before = -1;    //之前的状态点
__IO int16_t data_value_x_now = -1;       // 现在的状态点
__IO int16_t data_value_y_before = -1; 
__IO int16_t data_value_y_now = -1;

AD_Point  ad_point[NOFCHANEL];      //采样数据模块

static void GDScream_Data_show_init(void){       //显示数据AD的样式初始化
  uint8_t i=0 ;
	data_value_x_before = -1 ;
	data_value_x_now = -1;
	data_value_y_before = -1 ;
	data_value_y_now = -1;
	for( i=0;i<NOFCHANEL ;i++ ){
		ad_point[i].value_x_before =data_value_x_before; 
		ad_point[i].value_x_now  =  data_value_x_now;
		ad_point[i].value_y_before  = data_value_y_before ;
		ad_point[i].value_y_now =  data_value_y_now;
		ad_point[i].draw_point = Draw_point;
	}
	ad_point[0].para_color = CL_WHITE;
	ad_point[1].para_color = CL_GREEN;
	ad_point[2].para_color = CL_GREY3;
	ad_point[3].para_color = CL_YELLOW;
	ad_point[4].para_color = CL_BLUE;
	ad_point[5].para_color = CL_MAGENTA;
}

                                

static void Draw_point(void *draw_pot){      				//AD模块采样点的绘制功能
	AD_Point *ptr_point = (AD_Point *)draw_pot;
  if((ptr_point->value_x_before) == -1){
			ILI9341_SetPointPixel(ptr_point->value_x_now,ptr_point->value_y_now,1);
	}else{
		  ILI9341_DrawLine(ptr_point->value_x_before,ptr_point->value_y_before,ptr_point->value_x_now,ptr_point->value_y_now,1);
	}
}

void  GDScream_Data_show(int32_t *data_value , uint16_t data_num){  //GD显示 
  
  uint8_t i=0 , j=0 ;
  char cStr [ 100 ];	
	char * pStr = 0;
   float ADC_ValueLocal;
 
    int16_t data_value_x , data_value_y ;


	for(i=0 ; i<data_num;i++){
		ad_point[i].data_value = (int16_t) data_value[i];    //对数据进行模块存储,将采集到的数据一一存入采样点的实时存储寄存器
	}

  LCD_SetColors(CL_WHITE , CL_WHITE);                   
  if((data_value_x_now<0)||(data_value_x_now > LCD_GDSCAN_X_End-2)){   // 如果是第一次进入最左端存储点就刷新程序
		LCD_SetColors(CL_BLACK , CL_WHITE);						 
		ILI9341_DrawRectangle(LCD_GDSCAN_X_Start,
                        LCD_GDSCAN_Y_Start,                    
                        LCD_GDSCAN_X_LENGTH, 
                        LCD_GDSCAN_Y_LENGTH,1,1);
		GDScream_Line_Init();

    GDScream_Data_show_init();
 
	} 
  if(data_value_x_before == -1){  //说明是第一次     如果是初始化第一次需要在最左端绘制描绘点
		 for(i=0 ;i<data_num ;i++ ){
			 data_value_x =  LCD_GDSCAN_X_Start;
			 data_value_y =  LCD_GDSCAN_Y_End  -(ad_point[i].data_value/ HY) ;
			 data_value_x_now =  data_value_x ;
			 data_value_y_now =  data_value_y ;
			 ad_point[i].value_x_now = data_value_x_now;
			 ad_point[i].value_y_now = data_value_y_now;
			 LCD_SetColors(ad_point[i].para_color , ad_point[i].para_color);
			 ad_point[i].draw_point(&ad_point[i]);
			 //ILI9341_SetPointPixel(ad_point[i].data_value_x_now,ad_point[i].data_value_y_now,1);

			 data_value_x_before = data_value_x ;
			 data_value_y_before = data_value_y ;
			 ad_point[i].value_x_before = data_value_x_before;
			 ad_point[i].value_y_before = data_value_y_before;
		 }   
			 	
	}
	else {      
		 for(j=0 ;j<data_num ;j++ ){     //正常绘制注意当前数据与之前数据的切换
			 data_value_x  = data_value_x_before+DX  ;
			 data_value_y =  LCD_GDSCAN_Y_End  -(ad_point[j].data_value/ HY) ;
			 data_value_x_now =  data_value_x ;
			 data_value_y_now =  data_value_y ;
			 ad_point[j].value_x_now = data_value_x_now;
			 ad_point[j].value_y_now = data_value_y_now;
			 LCD_SetColors(ad_point[j].para_color , ad_point[j].para_color);
			 ad_point[j].draw_point(&ad_point[j]);
			 //ILI9341_DrawLine(ad_point[j].data_value_x_before,ad_point[j].data_value_y_before,ad_point[j].data_value_x_now,ad_point[j].data_value_y_now,1);

			 data_value_x_before = data_value_x_now ;
			 data_value_y_before = data_value_y_now ;
			 ad_point[j].value_x_before = data_value_x_before;
			 ad_point[j].value_y_before = data_value_y_before;
		 }	
	}


	ADC_ValueLocal =(float)ad_point[0].data_value/4096*3.3;

	sprintf ( cStr, "0x%04X",ad_point[0].data_value ); 
  LCD_SetColors(CL_MAGENTA,CL_WHITE);
	/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
	*中文字体大小是16*16的,需要其它字体请自行制作字模*/
	/*这个函数只对英文字体起作用*/
	LCD_SetFont(&Font8x16);
	ILI9341_DispString_EN_CH( LCD_GDControl_X_Start+2 , LCD_GDControl_Y_LENGTH - 50, cStr);

	sprintf ( cStr, "%.3fV",ADC_ValueLocal ); 
  LCD_SetColors(CL_RED,CL_WHITE);
	/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
	*中文字体大小是16*16的,需要其它字体请自行制作字模*/
	/*这个函数只对英文字体起作用*/
	LCD_SetFont(&Font8x16);
	ILI9341_DispString_EN_CH( LCD_GDControl_X_Start +2, LCD_GDControl_Y_LENGTH - 30, cStr);
}
 
 

该处使用的url网络请求的数据。


总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值