[STM32L4] STM32L4R5ZIT6U驱动PCF8591产生锯齿波

[复制链接]
461|0
 楼主| 比神乐 发表于 2023-4-27 12:11 | 显示全部楼层 |阅读模式
一开始想用硬件I2C,用STM32CubeMX生成的工程,出不来波形。
仿真了一下,确实不对,而且HAL库比较繁琐,不好查问题。
于是改为模拟时序。
SDA接PF1,SCL接PF2。
代码:
  1. #include "main.h"

  2. #define uchar unsigned char
  3. /* Private includes ----------------------------------------------------------*/
  4. /* USER CODE BEGIN Includes */
  5. #define SDA_0  HAL_GPIO_WritePin(GPIOF,GPIO_PIN_1,GPIO_PIN_RESET)
  6. #define SDA_1  HAL_GPIO_WritePin(GPIOF,GPIO_PIN_1,GPIO_PIN_SET)
  7. #define SCL_0  HAL_GPIO_WritePin(GPIOF,GPIO_PIN_2,GPIO_PIN_RESET)
  8. #define SCL_1  HAL_GPIO_WritePin(GPIOF,GPIO_PIN_2,GPIO_PIN_SET)
  9. #define SDA    HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_1)
  10. /* USER CODE END Includes */
  11. #define  PCF8591 0x90    //PCF8591 地址
  12. /* Private typedef -----------------------------------------------------------*/
  13. /* USER CODE BEGIN PTD */

  14. /* USER CODE END PTD */

  15. /* Private define ------------------------------------------------------------*/
  16. /* USER CODE BEGIN PD */

  17. /* USER CODE END PD */

  18. /* Private macro -------------------------------------------------------------*/
  19. /* USER CODE BEGIN PM */

  20. /* USER CODE END PM */

  21. /* Private variables ---------------------------------------------------------*/
  22. TIM_HandleTypeDef htim1;
  23. uchar ack;
  24. /* USER CODE BEGIN PV */

  25. /* USER CODE END PV */

  26. /* Private function prototypes -----------------------------------------------*/
  27. void SystemClock_Config(void);
  28. void MX_GPIO_Init(void);
  29. void MX_TIM1_Init(void);

  30. void delay_us(uchar x)
  31. {
  32.         uchar i,j;
  33.         for(i=0;i<x;i++)
  34.                 for(j=0;j<8;j++);
  35. }
  36. /* USER CODE BEGIN PFP */
  37. static void SDA_OUTPUT_Init(void)
  38. {
  39.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  40. /* USER CODE BEGIN MX_GPIO_Init_1 */
  41. /* USER CODE END MX_GPIO_Init_1 */

  42.   /* GPIO Ports Clock Enable */
  43.   __HAL_RCC_GPIOF_CLK_ENABLE();

  44.   /*Configure GPIO pin Output Level */
  45.   

  46.   /*Configure GPIO pins : PF0 PF1 */
  47.   GPIO_InitStruct.Pin = GPIO_PIN_1;
  48.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  49.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  50.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  51.   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  52. /* USER CODE BEGIN MX_GPIO_Init_2 */
  53. /* USER CODE END MX_GPIO_Init_2 */
  54. }
  55. /* USER CODE END PFP */
  56. static void SDA_INPUT_Init(void)
  57. {
  58.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  59. /* USER CODE BEGIN MX_GPIO_Init_1 */
  60. /* USER CODE END MX_GPIO_Init_1 */

  61.   /* GPIO Ports Clock Enable */
  62.   __HAL_RCC_GPIOF_CLK_ENABLE();

  63.   /*Configure GPIO pin Output Level */
  64.   

  65.   /*Configure GPIO pins : PF0 PF1 */
  66.   GPIO_InitStruct.Pin = GPIO_PIN_1;
  67.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  68.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  69.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  70.   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  71. /* USER CODE BEGIN MX_GPIO_Init_2 */
  72. /* USER CODE END MX_GPIO_Init_2 */
  73. }
  74. /* Private user code ---------------------------------------------------------*/
  75. /* USER CODE BEGIN 0 */
  76. /*******************************************************************
  77.                      起动总线函数               
  78. 函数原型: void  Start_I2c();  
  79. 功能:     启动I2C总线,即发送I2C起始条件.  
  80. ********************************************************************/
  81. void Start_I2c()
  82. {
  83.        
  84.         SDA_OUTPUT_Init();
  85.         delay_us(1);
  86.   SDA_1;         /*发送起始条件的数据信号*/
  87.   delay_us(1);
  88.   SCL_1;
  89.   delay_us(5);  
  90.   SDA_0;         /*发送起始信号*/
  91.   delay_us(5);      
  92.   SCL_0;       /*钳住I2C总线,准备发送或接收数据 */
  93.   delay_us(2);  
  94. }

  95. /*******************************************************************
  96.                       结束总线函数               
  97. 函数原型: void  Stop_I2c();  
  98. 功能:     结束I2C总线,即发送I2C结束条件.  
  99. ********************************************************************/
  100. void Stop_I2c()
  101. {
  102.         SDA_OUTPUT_Init();
  103.         delay_us(1);
  104.   SDA_0;      /*发送结束条件的数据信号*/
  105.   delay_us(1);    /*发送结束条件的时钟信号*/
  106.   SCL_1;      /*结束条件建立时间大于4μs*/
  107.   delay_us(5);
  108.   SDA_1;      /*发送I2C总线结束信号*/
  109.   delay_us(4);
  110. }

  111. /*******************************************************************
  112.                  字节数据发送函数               
  113. 函数原型: void  SendByte(UCHAR c);
  114. 功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  115.           此状态位进行操作.(不应答或非应答都使ack=0)     
  116.            发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
  117. ********************************************************************/
  118. void  SendByte(unsigned char  c)
  119. {
  120. unsigned char  BitCnt;
  121. SDA_OUTPUT_Init();
  122.         delay_us(1);
  123. for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
  124.     {
  125.      if((c<<BitCnt)&0x80)SDA_1;   /*判断发送位*/
  126.        else  SDA_0;               
  127.                         delay_us(1);
  128.                         SCL_1;               /*置时钟线为高,通知被控器开始接收数据位*/
  129.       delay_us(5);        
  130.      SCL_0;
  131.     }
  132.    
  133.     delay_us(2);
  134.     SDA_1;                /*8位发送完后释放数据线,准备接收应答位*/
  135.     delay_us(2);  
  136.     SCL_1;
  137.     delay_us(3);
  138.                 SDA_INPUT_Init();
  139.                 delay_us(1);
  140.     if(SDA==1)ack=0;     
  141.        else ack=1;        /*判断是否接收到应答信号*/
  142.     SCL_0;
  143.     delay_us(2);
  144. }

  145. /*******************************************************************
  146.                  字节数据接收函数               
  147. 函数原型: UCHAR  RcvByte();
  148. 功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  149.           发完后请用应答函数应答从机。  
  150. ********************************************************************/   
  151. unsigned char   RcvByte()
  152. {
  153.   unsigned char  retc;
  154.   unsigned char  BitCnt;
  155.   SDA_OUTPUT_Init();
  156.         delay_us(1);
  157.   retc=0;
  158.   SDA_1;                     /*置数据线为输入方式*/
  159.   for(BitCnt=0;BitCnt<8;BitCnt++)
  160.       {
  161.         delay_us(1);         
  162.         SCL_0;                  /*置时钟线为低,准备接收数据位*/
  163.         delay_us(5);
  164.         SCL_1;                  /*置时钟线为高使数据线上数据有效*/
  165.         delay_us(2);
  166.         retc=retc<<1;
  167.                                 SDA_INPUT_Init();
  168.                                 delay_us(1);
  169.         if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
  170.         delay_us(2);
  171.       }
  172.   SCL_0;   
  173.   delay_us(2);
  174.   return(retc);
  175. }

  176. /********************************************************************
  177.                      应答子函数
  178. 函数原型:  void Ack_I2c(bit a);
  179. 功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
  180. ********************************************************************/
  181. void Ack_I2c(uchar a)
  182. {
  183.   
  184.   if(a==0)SDA_0;              /*在此发出应答或非应答信号 */
  185.   else SDA_1;
  186.   delay_us(3);     
  187.   SCL_1;
  188.   delay_us(5);
  189.   SCL_0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  190.   delay_us(2);   
  191. }


  192. /*******************************************************************
  193. DAC 变换, 转化函数               
  194. *******************************************************************/
  195. uchar DACconversion(unsigned char sla,unsigned char c,  unsigned char Val)
  196. {
  197.    Start_I2c();              //启动总线
  198.    SendByte(sla);            //发送器件地址
  199.    if(ack==0)return(0);
  200.    SendByte(c);              //发送控制字节
  201.    if(ack==0)return(0);
  202.    SendByte(Val);            //发送DAC的数值  
  203.    if(ack==0)return(0);
  204.    Stop_I2c();               //结束总线
  205.    return(1);
  206. }



  207. /* USER CODE END 0 */

  208. /**
  209.   * [url=home.php?mod=space&uid=247401]@brief[/url]  The application entry point.
  210.   * @retval int
  211.   */
  212. int main(void)
  213. {
  214.   /* USER CODE BEGIN 1 */
  215.         uchar data=0;
  216.   /* USER CODE END 1 */

  217.   /* MCU Configuration--------------------------------------------------------*/

  218.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  219.   HAL_Init();

  220.   /* USER CODE BEGIN Init */

  221.   /* USER CODE END Init */

  222.   /* Configure the system clock */
  223.   SystemClock_Config();

  224.   /* USER CODE BEGIN SysInit */

  225.   /* USER CODE END SysInit */

  226.   /* Initialize all configured peripherals */
  227.   MX_GPIO_Init();
  228.   
  229.   /* USER CODE BEGIN 2 */

  230.   /* USER CODE END 2 */
  231.        
  232.   /* Infinite loop */
  233.   /* USER CODE BEGIN WHILE */
  234.   while (1)
  235.   {
  236.     /* USER CODE END WHILE */
  237.                 DACconversion(PCF8591,0x40, data); //DAC          数模转换
  238.                 data++;
  239.                 HAL_Delay(1);
  240.     /* USER CODE BEGIN 3 */
  241.   }
  242.   /* USER CODE END 3 */
  243. }

  244. /**
  245.   * @brief System Clock Configuration
  246.   * @retval None
  247.   */
  248. void SystemClock_Config(void)
  249. {
  250.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  251.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  252.   /** Configure the main internal regulator output voltage
  253.   */
  254.   if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  255.   {
  256.     Error_Handler();
  257.   }

  258.   /** Initializes the RCC Oscillators according to the specified parameters
  259.   * in the RCC_OscInitTypeDef structure.
  260.   */
  261.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  262.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  263.   RCC_OscInitStruct.MSICalibrationValue = 0;
  264.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  265.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  266.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  267.   {
  268.     Error_Handler();
  269.   }

  270.   /** Initializes the CPU, AHB and APB buses clocks
  271.   */
  272.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  273.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  274.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
  275.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  276.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  277.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  278.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  279.   {
  280.     Error_Handler();
  281.   }
  282. }


  283. /**
  284.   * @brief GPIO Initialization Function
  285.   * @param None
  286.   * @retval None
  287.   */
  288. static void MX_GPIO_Init(void)
  289. {
  290.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  291. /* USER CODE BEGIN MX_GPIO_Init_1 */
  292. /* USER CODE END MX_GPIO_Init_1 */

  293.   /* GPIO Ports Clock Enable */
  294.   __HAL_RCC_GPIOF_CLK_ENABLE();

  295.   /*Configure GPIO pin Output Level */
  296.   HAL_GPIO_WritePin(GPIOF, GPIO_PIN_2|GPIO_PIN_1, GPIO_PIN_RESET);

  297.   /*Configure GPIO pins : PF0 PF1 */
  298.   GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_1;
  299.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  300.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  301.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  302.   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  303. /* USER CODE BEGIN MX_GPIO_Init_2 */
  304. /* USER CODE END MX_GPIO_Init_2 */
  305. }

  306. /* USER CODE BEGIN 4 */

  307. /* USER CODE END 4 */

  308. /**
  309.   * @brief  This function is executed in case of error occurrence.
  310.   * @retval None
  311.   */
  312. void Error_Handler(void)
  313. {
  314.   /* USER CODE BEGIN Error_Handler_Debug */
  315.   /* User can add his own implementation to report the HAL error return state */
  316.   __disable_irq();
  317.   while (1)
  318.   {
  319.   }
  320.   /* USER CODE END Error_Handler_Debug */
  321. }

  322. #ifdef  USE_FULL_ASSERT
  323. /**
  324.   * @brief  Reports the name of the source file and the source line number
  325.   *         where the assert_param error has occurred.
  326.   * @param  file: pointer to the source file name
  327.   * @param  line: assert_param error line source number
  328.   * @retval None
  329.   */
  330. void assert_failed(uint8_t *file, uint32_t line)
  331. {
  332.   /* USER CODE BEGIN 6 */
  333.   /* User can add his own implementation to report the file name and line number,
  334.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  335.   /* USER CODE END 6 */
  336. }
  337. #endif /* USE_FULL_ASSERT */
效果图:
0.jpg


1.jpg


您需要登录后才可以回帖 登录 | 注册

本版积分规则

470

主题

3537

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部