ADX112驱动从0开始(STM32)
从0开始写ADX112驱动(STM32)
步骤1:CUBE_MX先选你要的芯片 我用的G070(最便宜的那颗)
步骤2:时钟配置 你要多大时钟直接拉满
步骤3:生成工程
步骤4:打开工程点开main.c里面 hal_conf.h 的头文件
步骤5:删除SPI的注释,这里我们要啥功能就删除什么东西的注释
步骤6:新建ADX112.c/ADX112.h文件
右键添加ADX112.c到工程
整完以后可以直接用VS Code 打开Keil工程
安装这个插件
然后就这样,那样
但是他不能直接跳转到,.h 文件之类,配置起来较为麻烦,还是直接写,配合KEIL就行
配置一下引脚,右键选择跳转到定义配置为输入引脚
写ADX112驱动的壳
使用Code block 可以直接运行C 不用配置什么环境
#include <stdio.h> #include <stdlib.h> #define DR_8SPS 0b0000000000000000 #define DR_16SPS 0b0000000000100000 #define DR_32SPS 0b0000000001000000 #define DR_64SPS 0b0000000001100000 #define DR_128SPS 0b0000000010000000 #define DR_250SPS 0b0000000010100000 #define DR_475SPS 0b0000000011000000 #define DR_860SPS 0b0000000011100000 #define MUX_PA0_NA1 0b0000000000000000 #define MUX_PA0_NA3 0b0001000000000000 #define MUX_PA1_NA3 0b0010000000000000 #define MUX_PA2_NA3 0b0011000000000000 #define MUX_PA0_NGND 0b0100000000000000 #define MUX_PA1_NGND 0b0101000000000000 #define MUX_PA2_NGND 0b0110000000000000 #define MUX_PA3_NGND 0b0111000000000000 #define MODE_CONTIUOUS 0b0000000000000000 #define MODE_POWERDOWN 0b0000000100000000 #define Single_Conversion_DIS 0b0000000000000000 #define Single_Conversion_SSC 0b1000000000000000 #define PGA_GAIN_6_144 0b0000000000000000 #define PGA_GAIN_4_096 0b0000001000000000 #define PGA_GAIN_2_048 0b0000010000000000 #define PGA_GAIN_0_024 0b0000011000000000 #define PGA_GAIN_0_512 0b0000100000000000 #define PGA_GAIN_0_256 0b0000101000000000 #define TS_MODE_ADC 0b0000000000000000 #define TS_MODE_TS 0b0000000000010000 #define PULL_UP_DOUT_PullupDis 0b0000000000000000 #define PULL_UP_DOUT_PullupEn 0b0000000000001000 #define NOP_UPdata_NUPConfig 0b0000000000000000 #define NOP_UPdata_UPConfig 0b0000000000000010 //ADX112结构体 typedef struct { int MUX; int PGA_GAIN; int DR; int MODE; int TS_MODE; int Single_Conversion; int PULL_UP_DOUT; int NOP; } ADX112_InitTypeDef; void ADX112_Get_ADValue(ADX112_InitTypeDef * Config) { int data; data=(Config->MUX)|(Config->PGA_GAIN)|(Config->DR)|(Config->MODE) |(Config->TS_MODE)|(Config->Single_Conversion)|(Config->PULL_UP_DOUT)|(Config->NOP); printf("%d\r\n",data); } int main() { ADX112_InitTypeDef ADX112_Init; ADX112_Init.MUX=MUX_PA0_NA3; ADX112_Init.PGA_GAIN=PGA_GAIN_6_144; ADX112_Init.DR= DR_16SPS; ADX112_Init.MODE=MODE_CONTIUOUS; ADX112_Init.PULL_UP_DOUT=PULL_UP_DOUT_PullupEn; ADX112_Init.Single_Conversion=Single_Conversion_DIS; ADX112_Init.TS_MODE=TS_MODE_ADC; while(1) { ADX112_Get_ADValue(&ADX112_Init); } return 0; } |
运行结果如下,是我们所期望的值
SPI数据发送CYCLE
咱们使用16位数据传输格式 (下图来自ADX112手册)
If CONFIG REGISTER data are not required to be read back, the ADX112 conversion data can also be clocked out in a short 16-bit data transmission cycle, as shown in Figure 23. Therefore, CS must be taken high after the 16th SCLK cycle. Taking CS high resets the SPI interface. The next time CS is taken low, data transmission starts with the currently buffered conversion result on the first SCLK rising edge. If DOUT/DRDY is low when data starts, the conversion buffer is already updated with a new result. Otherwise, if DOUT/DRDY is high, the same result from the data transmission cycle is read.
SCLK 时序图如上,下降沿传输数据
综合壳和SPI底层驱动
ADX112.C文件
#include "ADX112.h" void ADX112_GPIO_Init(void) { //初始化ADX112要用的GPIO static GPIO_InitTypeDef GPIO_InitStruct = {0}; //使能各个引脚的时钟 CS_PORT_CLK_ENABLE; SCLK_PORT_CLK_ENABLE; MISO_PORT_CLK_ENABLE; MOSI_PORT_CLK_ENABLE; //配置各个引脚
//CS 引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = CS_PIN; HAL_GPIO_Init(CS_PORT, &GPIO_InitStruct); //MOSI 引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = MOSI_PIN; HAL_GPIO_Init(MOSI_PORT, &GPIO_InitStruct); //SCLK 引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = SCLK_PIN; HAL_GPIO_Init(SCLK_PORT, &GPIO_InitStruct); //MISO 引脚 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = MISO_PIN; HAL_GPIO_Init(MISO_PORT, &GPIO_InitStruct); CS_H; SCLK_H; MOSI_L; } //配置ADX112 读写 uint16_t ADX112_Get_ADValue(ADX112_InitTypeDef* Config) { uint16_t data,i,wdata; //将结构体指针的参数赋值给wdata wdata=(Config->MUX)|(Config->PGA_GAIN)|(Config->DR)|(Config->MODE) |(Config->TS_MODE)|(Config->Single_Conversion)|(Config->PULL_UP_DOUT)|(Config->NOP);
//拉低时钟开始传输数据 CS_L; for (i = 0; i < 16; i++) { SCLK_H; data<<=1; //如果最高位为1则写1否则写0 if((wdata&0X8000)==0X8000) { MOSI_H; } else { MOSI_L; } //如果MISO 是高则最低位加1 //如果MISO 是低则不加 data=data+MISO; SCLK_L; //每次传输完一个数据 配置左移一位 wdata<<=1;
} CS_H; return data; } |
ADX112.h文件
//定义头文件名字 #ifndef __ADX112_H #define __ADX112_H //用的MCU什么型号写啥 我这里用的是G0 所以拷贝这个 #include "stm32f4xx_hal.h" //宏定义 将MOSI的PIN指定到那个PIN #define MOSI_PIN GPIO_PIN_3 #define MISO_PIN GPIO_PIN_1 #define SCLK_PIN GPIO_PIN_2 #define CS_PIN GPIO_PIN_10 //定义SPI所使用的端口 //换MCU或者改端口时候直接改宏定义就好了 #define MOSI_PORT GPIOA #define MISO_PORT GPIOA #define SCLK_PORT GPIOA #define CS_PORT GPIOA //定义各个引脚的时钟 #define CS_PORT_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE() #define SCLK_PORT_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE() #define MISO_PORT_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE() #define MOSI_PORT_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE() //定义引脚输出输入代号 可以少打点字 #define CS_H HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_SET) #define CS_L HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_RESET) #define MOSI_H HAL_GPIO_WritePin(MOSI_PORT,MOSI_PIN,GPIO_PIN_SET) #define MOSI_L HAL_GPIO_WritePin(MOSI_PORT,MOSI_PIN,GPIO_PIN_RESET) #define SCLK_H HAL_GPIO_WritePin(SCLK_PORT,SCLK_PIN,GPIO_PIN_SET) #define SCLK_L HAL_GPIO_WritePin(SCLK_PORT,SCLK_PIN,GPIO_PIN_RESET) #define MISO HAL_GPIO_ReadPin(MISO_PORT,MISO_PIN) //定义ADX112的配置 #define DR_8SPS 0x0000 #define DR_16SPS 0x0020 #define DR_32SPS 0x0040 #define DR_64SPS 0x0060 #define DR_128SPS 0x0080 #define DR_250SPS 0x00a0 #define DR_475SPS 0x00c0 #define DR_860SPS 0x00e0 #define MUX_PA0_NA1 0x0000 #define MUX_PA0_NA3 0x1000 #define MUX_PA1_NA3 0x2000 #define MUX_PA2_NA3 0x3000 #define MUX_PA0_NGND 0x4000 #define MUX_PA1_NGND 0x5000 #define MUX_PA2_NGND 0x6000 #define MUX_PA3_NGND 0x7000 #define MODE_CONTIUOUS 0x0000 #define MODE_POWERDOWN 0x0100 #define Single_Conversion_DIS 0x0000 #define Single_Conversion_SSC 0x8000 #define PGA_GAIN_6_144 0x0000 #define PGA_GAIN_4_096 0x0200 #define PGA_GAIN_2_048 0x0400 #define PGA_GAIN_0_024 0x0600 #define PGA_GAIN_0_512 0x0800 #define PGA_GAIN_0_256 0x0a00 #define TS_MODE_ADC 0x0000 #define TS_MODE_TS 0x0010 #define PULL_UP_DOUT_PullupDis 0x0000 #define PULL_UP_DOUT_PullupEn 0x0008 #define NOP_Pdata_NPConfig 0x0000 #define NOP_Pdata_PConfig 0x0002 //ADX112结构体 typedef struct { uint16_t MUX; uint16_t PGA_GAIN; uint16_t DR; uint16_t MODE; uint16_t TS_MODE; uint16_t Single_Conversion; uint16_t PULL_UP_DOUT; uint16_t NOP; } ADX112_InitTypeDef; //将ADX112 各个bit 信息拷贝至此 /************************************** * ADX112 Register CONFIG ************************************** * Bit 15 / Single Conversion * Bit 14 / MUX * Bit 13 / MUX * Bit 12 / MUX * Bit 11 / PGA * Bit 10 / PGA * Bit 9 / PGA * Bit 8 / MODE * Bit 7 / DR * Bit6 / DR * Bit5 / DR * Bit4 / TS_MODE * Bit3 / PULL_UP_DOUT * Bit2 / NOP * Bit1 / NOP * Bit 0 / Reserved * |15-12 |11-8 |7-4 |3-0| * 8421 8421 8421 8421 * 0~~~ 0100 1000 0010 * *************************************/ /************************************ MUX=100 AINP = AIN0 0x4 MUX=101 AINP = AIN1 0x5 MUX=110 AINP = AIN2 0x6 MUX=111 AINP = AIN3 0x7 FULL SCALE RANGE => 2.048 V DATE RATE => 860 SPS
************************************/ /* ADX112 初始化 */ void ADX112_GPIO_Init(void); uint16_t ADX112_Get_ADValue(ADX112_InitTypeDef * Config); #endif |
后续将ADX112_Init改为ADX112_GPIO_Init 避免混淆
验证SPI
Main.c
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2022 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "ADX112.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) {
/* USER CODE BEGIN 1 */ ADX112_InitTypeDef ADX112_Init; uint16_t ADC_Value; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */ /* Initialize all configured peripherals */ /* USER CODE BEGIN 2 */ ADX112_GPIO_Init();
ADX112_Init.MUX=MUX_PA0_NA3; ADX112_Init.PGA_GAIN=PGA_GAIN_6_144; ADX112_Init.DR= DR_16SPS; ADX112_Init.MODE=MODE_CONTIUOUS; ADX112_Init.PULL_UP_DOUT=PULL_UP_DOUT_PullupEn; ADX112_Init.Single_Conversion=Single_Conversion_DIS; ADX112_Init.TS_MODE=TS_MODE_ADC; ADC_Value=ADX112_Get_ADValue(&ADX112_Init); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ ADC_Value=ADX112_Get_ADValue(&ADX112_Init); HAL_Delay(500); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1; RCC_OscInitStruct.PLL.PLLN = 8; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
没有挂ADX112时候逻辑分析仪输出
满足我们的设定,OK 挂上芯片就刚好。