前言:我们在单片机的项目开发过程中经常会遇到使用新IC芯片的情况,某宝卖家有个时候也提供不了对应开发程序,到网上找资料也找不到;很多初学者面对这样的问题往往束手无策,这里我给大家介绍我经常用的其中一种新IC调试的方法。
因为这个芯片比较简单我这里采用下面步骤进行:
第一步:先用arduino+面包板快速搭建电路验证芯片功能
第二步:使用STM32CubeIDE快速搭建工程验证在STM32上工作是否正常
Tips:由于我手头没有万用表,这里我使用arduino的模拟电压采集功能通过串口打印出来作为电位计的电压监控用。
首先,我们先快速浏览芯片数据手册,获取重要信息
IC型号:TPL0501
电压范围:2.7~5.5V
温度范围:-40~125℃
通信方式:SPI
阻值:100KΩ
阻值偏差:±20%
该芯片是某州仪器的一款单通道数字电位计,通信方式是SPI总线,单方向的,即只能控制芯片,不能读取输入数据,下面是数据手册的具体介绍。
环境参数:主要包括温度使用范围、电压使用范围、误差、温度漂移以及实物引脚对应关系都在这里
功能框图:主要介绍该芯片的内部组成和工作原理
引脚定义:每个引脚的功能介绍
SPI通信说明:主要介绍芯片的通信方式,这个芯片因为没有设置模式功能,只需要对芯片直接写数据即可,通信方式与我们所使用的74HC595的方式类似
真值对照表:也就是数字量对应的实际电阻值,我这里只截取了一部分,剩下的大家可以自行去参考详细手册
对于要调通这个芯片这些介绍基本满足我们的需求了
芯片模块的快速制作
在芯片商城上买了两片回来调试,芯片购买的费用小伙伴给付了
准备好芯片+转接板
焊接两块是为了防止在使用过程中意外弄坏另一块可以立马补上,确保调试正常进行而不耽误太多时间
焊接好排针,并在供电端加上0.1uF的滤波电容,降低高频供电干扰
这样我们的模块就制作完成了
arduino快速搭建工程
arduino uno 引脚4 -> CLK
arduino uno 引脚5 -> DIN
arduino uno 引脚6 -> CS
arduino uno 引脚5v -> VCC、VREF
arduino uno 引脚GND -> GND、L
arduino uno 引脚A0 -> VRES_OUT
首先用面包板+杜邦线搭好电路
说明:我在这里使用的供电电压和数字电位计参考电压都是使用的5V,相应的输出结果也是在0~5V范围
然后使用arduino自带的库,编写代码,再变动阻值参数,看下输出的实际结果和真值表是否对应的上
数值为0x00时对应的模拟电压输出
数值为0x88时对应的模拟电压输出
数值为0xFF时对应的模拟电压输出
经过验证,在arduino上跑没有问题,接下来我们准备在STM32上去运行
arduino代码部分:
/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the Serial Monitor.
Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu).
Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/AnalogReadSerial
*/
int CS_Pin = 6;
int CLK_Pin = 4;
int DIN_Pin = 5; //这里定义了那三个脚
// the setup routine runs once when you press reset:
void setup() {
pinMode(CS_Pin,OUTPUT);
pinMode(CLK_Pin,OUTPUT);
pinMode(DIN_Pin,OUTPUT); //让三个脚都是输出状态
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
digitalWrite(CS_Pin,LOW);
shiftOut(DIN_Pin,CLK_Pin,MSBFIRST,0xFF);
digitalWrite(CS_Pin,HIGH);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
float voltage= sensorValue * (5.0 / 1023.0); //换算成电压
// print out the value you read:
Serial.println(voltage,DEC);
delay(100); // delay in between reads for stability
}
STM32搭建工程验证
说明:STM32使用的供电电压和数字电位计参考电压都是3V3,相应的输出结果也是在0~3V3范围
引脚对应关系:
PA4 -> CLK
PA5 -> DIN
PA6 -> CS
3V3 -> VCC、VREF
arduino uno 引脚GND -> GND、L
arduino uno 引脚A0 -> VRES-OUT
开发板+面包板搭建电路
用STM32CubeIDE建立一个工程
配置好PA4、PA5、PA6引脚为输出
生成代码,并添加TPL0501的驱动代码
编译看运行的效果,输入值为0x55
更改输入的数值为0x22,验证是否正确
main函数代码部分:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 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"
/* 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 */
#define TLP0501_DIN_H() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)
#define TLP0501_DIN_L() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
#define TLP0501_CS_H() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET)
#define TLP0501_CS_L() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET)
#define TLP0501_CLK_H() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define TLP0501_CLK_L() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
/* 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);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void TLP0501_WriteByte( uint8_t data )
{
uint8_t j;
for ( j=8; j>=1; j--)
{
TLP0501_CLK_L();
__NOP();
if(data & 0x80 ){ TLP0501_DIN_H(); }
else { TLP0501_DIN_L(); }
data <<= 1;
TLP0501_CLK_H();
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* 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 */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
TLP0501_CS_L();
TLP0501_WriteByte(0x22);
TLP0501_CS_H();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* 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};
/** 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.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pins : PA4 PA5 PA6 */
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* 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 */
/* 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,
tex: 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****/
总结:
1、这里介绍了众多新IC芯片调试方式中的一种,后期有机会再陆续介绍其他IC或新模块的调试方法。
2、文中只是简单的对芯片进行功能测试,实际项目中还会有移植、驱动的可靠性、稳定性等测试工作 。
3、我们要善于运用手头的工具、arduino等快速验证开发环境;模块的快速验证,特别是在项目开发过程中,时间就是金钱,对每一种工具的熟练掌握也是单片机开发过程中不可或缺的重要技能。
4、硬件调试与软件调试有很大的区别,很多时候是一次性,不可逆转的,不像软件Ctl+Z可以撤销;硬件在使用过程中出现意外损坏情况很正常:焊接不当、意外插错,静电防护不到位等等;我们要善于运用一些项目技巧,权衡时间或花费;这里之所以选择焊接两个芯片模块也是为了防止这种意外的发生而对调试造成不必要的时间耽搁。