STM32管脚模拟协议驱动双路16位DAC芯片TM8211

news2024/12/24 2:16:34

STM32管脚模拟协议驱动双路16位DAC芯片TM8211

TM8211是一款国产的低成本双路16位DAC驱动芯片,可以应用于普通数模转换领域及音频转换领域等。这里介绍STM32 HAL库驱动TM8211的逻辑,时序和代码。

TM8211的功能特性为:
在这里插入图片描述
TM8211的内部电路功能框图为:
在这里插入图片描述

TM8211驱动逻辑

TM8211支持典型的3.3V供电和5V供电,在驱动后进行电压输出时,需要注意,如以3.3V供电为例,并非是驱动输出0~3.3V的范围,而是半范围,即驱动输出的电压范围为0.825V – 2.475V (1/4VDD-- 3/4VDD)。

TM8211的管脚定义为:
在这里插入图片描述
在这里插入图片描述
其中控制管脚为WS, BCK和DIN,LCH和RCH为两个输出通道,介绍如下:
WS: 高电平指示对LCH通道进行配置,低电平指示对RCH通道进行配置
BCK:配置过程的时钟线,TM8211在时钟上升沿锁存数据,在WS的某个电平状态,前16个时钟锁存的数据有效,后面的忽略
DIN: 配置过程的数据线

TM8211典型应用

TM8211可应用于双通道音频输出,如:
在这里插入图片描述
也可以控制输出交流波形,通过隔直电容去掉直流电压部分。

工程配置

TM8211的配置时钟最大可达18.4MHz,在不需要配置MHz级信号输出控制时,可以采用GPIO管脚模拟协议对TM8211输出电压进行控制。这里介绍STM32CUBEIDE开发平台,以STM32G030F6P6为例,GPIO管脚模拟协议配置TM8211的范例。需要进行更高速配置时则需要调整为SPI硬件接口驱动。

首先建立基本工程并配置时钟:
在这里插入图片描述
在这里插入图片描述
配置3个GPIO作为驱动接口:
在这里插入图片描述
保存并生成初始工程代码:
在这里插入图片描述

工程代码:

工程代码实现都在main.c文件里,代码里用到的微秒延时函数参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化

两个通道都实现为类似正弦波的连续波形输出:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define TM8211_WS_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define TM8211_WS_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define TM8211_BCK_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
#define TM8211_BCK_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)
#define TM8211_DIN_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET)
#define TM8211_DIN_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET)
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{
  __IO uint32_t firstms, secondms;
  __IO uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}

void PY_usDelayOptimize(void)
{
  __IO uint32_t firstms, secondms;
  __IO float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}


void PY_Delay_us(uint32_t Delay)
{
  __IO uint32_t delayReg;

  __IO uint32_t msNum = Delay/1000;
  __IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* 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 */
#define us_num 2

void TM8211_OUTPUT_CONFIG(uint16_t LCH, uint16_t RCH)
{
	uint8_t i;
	TM8211_WS_L;
	PY_Delay_us_t(us_num);

	for(i=0; i<16; i++)
	{
		TM8211_BCK_L;
		if( (RCH>>(15-i))&0x0001 ) TM8211_DIN_H;
		else TM8211_DIN_L;
		PY_Delay_us_t(us_num);
		TM8211_BCK_H;
		PY_Delay_us_t(us_num);
	}

	PY_Delay_us_t(us_num);

	TM8211_WS_H;
	PY_Delay_us_t(us_num);
	for(i=0; i<16; i++)
	{
		TM8211_BCK_L;
		if( (LCH>>(15-i))&0x0001 ) TM8211_DIN_H;
		else TM8211_DIN_L;
		PY_Delay_us_t(us_num);
		TM8211_BCK_H;
		PY_Delay_us_t(us_num);
	}

	PY_Delay_us_t(us_num);
	TM8211_WS_L;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  uint16_t C1 = 0, C2 = 0;

  /* 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 */
  PY_usDelayTest();
  PY_usDelayOptimize();

  TM8211_OUTPUT_CONFIG(0x0000, 0x0000);
  PY_Delay_us_t(5000000);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	for(uint16_t i=0x8000; i<0xffff; i++)
	{
		C1=C2=i;
		TM8211_OUTPUT_CONFIG(C1, C2);
	}

	for(uint16_t j=0x0000; j<0x7fff; j++)
	{
		C1=C2=j;
		TM8211_OUTPUT_CONFIG(C1, C2);
	}

	for(uint16_t j=0x7fff; j>0x0000; j--)
	{
		C1=C2=j;
		TM8211_OUTPUT_CONFIG(C1, C2);
	}

	for(uint16_t i=0xffff; i>0x8000; i--)
	{
		C1=C2=i;
		TM8211_OUTPUT_CONFIG(C1, C2);
	}
    /* 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};

  /** 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();
  }
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA4 PA5 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* 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 */

其中,配置值和输出电压的关系参考如下测试结果(3.3V供电)了解:
在这里插入图片描述
如果要应用供电参考电压全范围输出的双路16位DAC,则参考:STM32模拟SPI时序控制双路16位数模转换(16bit DAC)芯片DAC8552电压输出

例程下载

STM32G030F6P6管脚模拟协议驱动双路16位DAC芯片TM8211例程

–End–

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/636126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一个人最大的愚蠢,就是 “习惯性反驳”

作者| Mr.K 编辑| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) 每个人都有“反驳的义务”&#xff0c;这是全球顶级咨询公司麦肯锡&#xff0c;对所有员工的行为要求&#xff0c;即对于自己不认同的看法和意见&#xff0c;明确表示出自己的想法并提出反驳。麦肯锡认…

揭秘报表新玩法!标配插件不再单调,手把手教你如何在浏览器中引入柱形图插件。

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 图表作为一款用于可视化数据的工具&#xff0c;可以帮助我们更好的分析和理解数…

【Rust日报】2023-06-10

nt-apiset: 一个用于 WindowsAPI API Set Map文件 的 Rust 解析器 我的bootloader程序项目的下一个构建块已经准备好了&#xff01;Nt-apiset 是用 Rust 编写的用于 Windows10及更高版本的 API Set Map 文件的解析器。 API Set是名称以“ API-”或“ ext-”开头的 PE 可执行文件…

【MySQL】View 视图用法及作用

文章目录 1. 视图概述1.1 为什么使用视图&#xff1f;1.2 视图的理解 2. 创建视图2.1 创建单表视图2.2 创建多表联合视图2.3 基于视图创建视图 3. 查看视图4. 更新视图的数据4.1 一般情况4.2 不可更新的视图 5. 删除视图6. 总结6.1 视图优点6.2 视图缺点 1. 视图概述 1.1 为什么…

STL之优先级队列(堆)的模拟实现与仿函数(8千字长文详解!)

STL之优先级队列&#xff08;堆&#xff09;的模拟实现与仿函数 文章目录 STL之优先级队列&#xff08;堆&#xff09;的模拟实现与仿函数优先级队列的概念priority_queue的接口介绍优先级队列的构造函数 priority_queue模拟实现类成员构造函数向下调整算法——正常实现 push向…

正负10V电压输入±电流输出伺服阀控制器

10V、4~20mA模拟指令输入伺服阀放大器是一种控制元件&#xff0c;用于控制液压系统中的比例阀或伺服阀。它主要由三个部分组成&#xff1a;比例阀或伺服阀、放大器。 比例阀或伺服阀是控制流量或压力的元件&#xff0c;它的输出信号通常是电压或电流。放大器用于将实际值转换为…

微信小程序开发uni-app-8分钟上手开发

本篇文章uni-app微信小程序开发-8分钟上手开发 -首先到微信小程序官网登录/注册微信小程序 微信小程序官网 uni-app 微信小程序 注册微信小程序 这里要注意&#xff1a; 激活邮箱之后&#xff0c;选择主体类型为 “个人类型”&#xff0c;并按要求登记主体信息。主体信息提…

一种直流转交流的代码实现 - through FFT

# show how to use FFT, filtered DC signal and return back to SampleValue-time zone. # the basic concept is coming from ChatGPT. # Write in python language. # # created by twicave. # Jun09,2023 # import numpy as np import matplotlib.pyplot as plt# 定义正弦信…

【C# 10 和 .NET 6】构建和使用 Web 服务(第16章)

Building and Consuming Web Services 构建和使用 Web 服务 本章介绍如何使用 ASP.NET Core Web API 构建 Web 服务&#xff08;也称为 HTTP 或 REST 服务&#xff09;&#xff0c;以及如何使用 HTTP 客户端使用 Web 服务&#xff0c;这些客户端可以是任何其他类型的 .NET 应用…

Qt信号和槽

一、定义 信号与槽&#xff08;Signal & Slot&#xff09;是 Qt 编程的基础&#xff0c;也是 Qt 的一大创新。因为有了信号与槽的编程机制&#xff0c;在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。 信号&#xff08;Signal&#xff09;就是在特定情况下被发…

基于SpringBoot+vue的毕业生信息招聘平台设计和实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

淘宝618每日一猜答案6月12日 源氏木语获得多少个奖项?

淘宝6月12日每日一猜答案是什么&#xff1f;&#xff0c;接下来也会给大家来介绍一下6月12日淘宝大赢家每日一猜的答案。 淘宝每日一猜6月12日答案分享 活动问题&#xff1a;源氏木语获得多少个奖项&#xff1f; 活动答案&#xff1a;【15】 注意是阿拉伯数字&#xff01; …

20230612 set1打卡

哈希表理论基础 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

FPGA驱动FT601实现USB3.0相机 OV5640视频采集 提供2套工程源码和QT上位机源码

目录 1、前言2、FT601芯片解读和时序分析FT601功能和硬件电路FT601读时序解读FT601写时序解读 3、我这儿的 FT601 USB3.0通信方案4、vivado工程1--彩条视频采集传输详细设计框图及其原理vivado工程解读 5、vivado工程2--OV5640视频采集传输详细设计框图及其原理vivado工程解读 …

【几分醉意赠书活动 - 04期】 | 《C++、Linux、算法等系列众书》

个人主页&#xff1a; 几分醉意的CSDN博客主页_传送门 个人主页&#xff1a; 陈老板的CSDN博客主页_传送门 赠书活动 | 第四期 本期好书推荐&#xff1a;《C、Linux、算法等系列众书》 粉丝福利&#xff1a;书籍赠送&#xff1a;共计送出30本 参与方式&#xff1a;关注公众号&a…

【MySQL 数据查询】: 基本、分组、排序、聚合、分页、条件查询详解

前言 ✨欢迎来到小K的MySQL专栏&#xff0c;本节将为大家带来MySQL数据查询的讲解&#xff08;基本、分组、排序、聚合、分页、条件查询&#xff09; 目录 前言一、基本查询二、条件查询三、聚合函数(统计函数)四、分组查询五、排序查询五、分页查询六、总结 一、基本查询 MySQ…

全网最简单的软渲染器

引言 本文实现了一个包含矩阵变化、光栅化、面剔除、深度测试等功能的软渲染器。所谓软渲染器就是使用 CPU 渲染 3D 模型的程序。因此请记住我们的最终目的&#xff1a;将3D模型显示在屏幕上 。本文分为两个部分&#xff1a;预备知识、渲染器核心实现。预备知识概述了简化的渲…

可以在手机上使用的提醒事项软件有哪些

随着科技的进步&#xff0c;越来越多的人选择使用各种手机软件来提高自己的效率&#xff0c;高效率的手机软件已经成为人们生活和工作中不可或缺的一部分。其中&#xff0c;提醒事项软件是一种非常实用的工具&#xff0c;可以督促用户按时完成任务&#xff0c;有效防止遗忘。 …

chatgpt赋能python:如何利用Python在网上赚钱:一份SEO指南

如何利用Python在网上赚钱&#xff1a;一份SEO指南 随着互联网的快速发展和Python成为一种越来越受欢迎的编程语言&#xff0c;越来越多的人开始利用Python在网上赚取额外的收入。本篇文章将介绍一些Python工具和技术&#xff0c;以及SEO最佳实践&#xff0c;帮助你利用Python…

Spring Boot 回顾

Spring Boot 的发展是很快的&#xff0c;也使用了很多年。但是在工作中&#xff0c;还是发现了很多公司还没有怎么使用 Spring Boot&#xff0c;依旧是在使用 Spring MVC。于是决定复习总结一下。框架的进步和飞跃很重要&#xff0c;但是也不能一味追求新鲜事物&#xff0c;历史…