我是靠谱客的博主 能干红牛,最近开发中收集的这篇文章主要介绍外设SPI控制AD9834输出正弦波基于STM32F103C8核心板的AD9834控制程序学习笔记,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

基于STM32F103C8核心板的AD9834控制程序学习笔记

最近做项目需要产生正弦波用于调制解调,为了输出一定频率的正弦波,选择了AD9834芯片,这是一款输出频率高达37.5 MHz的DDS芯片,通过三线SPI进行通讯。为了控制该芯片,选用STM32F103C8核心板与该芯片进行SPI通信。
关于SPI通信原理和特点,这里就不再赘述,网上很多资料可以辅助我们学习。
本次使用的是STM32CubeMx进行配置和初始化,使用HAL库进行编程实现控制。

  1. 原理说明

AD9834芯片有2个频率寄存器,2个相位寄存器,1个控制寄存器需要写入数据从而实现控制。
频率寄存器:28位,该芯片输出信号的频率由

f = ∆Phase × fMCLK/228

计算得到,其中∆Phase值即为频率寄存器中的值。
控制寄存器:16位,每一位有不同的控制作用,详细请参考数据手册。
相位寄存器:输出信号会经过如下的相位偏移

2π/4096 × PHASEREG

其中PHASEREG值即为相位寄存器中的值。

由此可知,为了实现控制AD9834,我们需要通过SPI通信将数据写入这些寄存器。下面就是本文的重点,如何实现STM32F103C8和AD9834之间的硬件SPI通信。当然,模拟GPIO实现SPI通信也是完全可行的,网上也有很多相关程序,这里就不做讲解了。

  1. STM32CubeMx配置要点

在配置SPI时主要考虑 SPI工作模式、数据格式、MSB或LSB、时钟频率、CPOL、CPHA、NSS工作模式这几项。

配置选项Value
工作模式全双工主机
数据格式16BIT
FIRST BITMSB
时钟频率16Mb(与系统时钟有关)
CPOLHIGH(空闲高电平)
CPHA1EDGE(这里是下降沿)
NSSSOFTWARE(程序控制)

以上参数的取值参考AD9834的数据手册,其中
CPOL在数据手册上给的是LOW即空闲时为低电平,但我在实际使用时发现需要设置为HIGH才能正常通信,这点还需要我深入学习其原因
另外NSS通过软件控制置即为在程序中控制一个额外的GPIO用于片选信号的传输。
值得注意的是,如果使用软件控制GPIO当作NSS信号,则最好为该GPIO配置一个下拉信号
这是由于我通过逻辑分析仪发现,如果软件控制NSS信号配置为不拉高也不拉底,则在通信过程中片选信号出现了随机跳变,目前我还没有发现这一干扰是如何产生的,因此为其配置GPIO Pull-down避免这一干扰的影响。这点也是后续我需要深入学东西的地方。
此外,阅读AD9834的数据手册发现FSELECT和PSELECT引脚在不使用时应该接CMOS高电平或低电平,因此最好额外配置GPIO输出管脚与之相连。

  1. 使用HAL的程序编写

配置完成之后就可以点击Generate Code 生成代码了。由于使用的是HAL库,并且需要传输的数据很少,因此使用其中的查询模式函数即可。本次只需要发送数据,因此只使用了HAL_SPI_Transmit函数。其定义如下。

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

需要注意的是这个函数中的第二个参数,其定义为uint8_t,但是我们进行16bit通信时需要发送uint6_t的数据,这点困扰了我很久
但是我们详细看HAL库中源代码可以发现,实际上这个函数时可以使用的。这个函数定义中有:

/* Transmit data in 16 Bit mode */
  if (hspi->Init.DataSize == SPI_DATASIZE_16BIT)
  {
    if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U))
    {
      hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
      hspi->pTxBuffPtr += sizeof(uint16_t);
      hspi->TxXferCount--;
    }
    /* Transmit data in 16 Bit mode */
    while (hspi->TxXferCount > 0U)
    {
      /* Wait until TXE flag is set to send data */
      if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
      {
        hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
        hspi->pTxBuffPtr += sizeof(uint16_t);
        hspi->TxXferCount--;
      }
      else
      {
        /* Timeout management */
        if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }

也就是说它实际上使用的存储单元是16位的,而C语言规定*a代表a中存储的地址对应的存储单元中的数据,即所定义的uint8_t是不影响后续数据使用的。
我们可以通过下面的函数实现一个16位数据的发送。

void SPI_Write_16Bits(uint16_t transdata)
{
	HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET);
	uint16_t arrofdata[1];
	arrofdata[0]=transdata;
	HAL_SPI_Transmit(&hspi1, (uint8_t* )arrofdata, 1, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);
}

注意,HAL_GPIO_WritePin用于程序控制GPIO模拟片选信号,通信前拉低通信后拉高。HAL_SPI_Transmit中第三个参数是需要发送的数据个数。当其为n时,就会连续发送16n个时钟脉冲用于数据传输(数据格式16位的情况下)。

之后我们在main.c中写主体程序

 /* USER CODE BEGIN 2 */
	HAL_Delay(1000);//延迟1000ms
	HAL_GPIO_WritePin(GPIOB,SPI_FS_Pin,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOB,SPI_PS_Pin,GPIO_PIN_RESET);
		
	SPI_Write_16Bits(0x2100);//RESET
	SPI_Write_16Bits(0XC000);//相位寄存器写0
	SPI_Write_16Bits(0x2100);//RESET

	SPI_Write_16Bits(0x2000);//写控制位 连续写入
	SPI_Write_16Bits(0x4937);//400kHz的后14位
	SPI_Write_16Bits(0x4106);//400kHz的前14位
	
	SPI_Write_16Bits(0x2800);
	SPI_Write_16Bits(0x926E);//800kHz的后14位
	SPI_Write_16Bits(0x820C);//800kHz的后14位
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_Delay(1000);
		SPI_Write_16Bits(0x2808);//选择频率寄存器1
		HAL_Delay(1000);
		SPI_Write_16Bits(0x2008);//选择频率寄存器0
  }
  /* USER CODE END 3 */
  1. 总结

工欲善其事必先利其器。想要测试自己写的代码是否正确,一定要有相应的一期可以方便随时找出错误。本次学习用到了逻辑分析仪和示波器。其中逻辑分析仪可以方便的找出管脚输出电平的问题,帮助非常大。示波器用来验证结果,简洁可视。
他山之石可以攻玉。一定要多从网上学习相关知识,看看别人程序是怎么实现的,区别在哪里。网上大佬不计其数,分享的学习资料多如繁花,一定要善于查找资料,提高自学能力,才能达到自己想要的结果。

最后

以上就是能干红牛为你收集整理的外设SPI控制AD9834输出正弦波基于STM32F103C8核心板的AD9834控制程序学习笔记的全部内容,希望文章能够帮你解决外设SPI控制AD9834输出正弦波基于STM32F103C8核心板的AD9834控制程序学习笔记所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部