查看: 1045|回复: 0
收起左侧

第四十三章:CH32V103应用教程——I2C-DMA,主机接收从机发送

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-28 14:32:27 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 17:31 编辑

    本章教程主要在前面第42章的基础上进行DMA模式下的主机接收从机发送实验。
    注意,本章例程使用CH32V103硬件IIC。


    1、I2C简介及相关函数介绍

    关于I2C相关介绍,在前面章节已经介绍,在此不再赘述。
    关于CH32V103各模式介绍以及具体信息,可参考CH32V103应用手册。I2C标准库函数在第十四章节已介绍,在此不再赘述。


    2、硬件设计

    本章教程使用开发板硬件I2C进行主机发送从机接收实验,需用到两个开发板,将两个开发板对应IIC引脚连接起来即可。
    注意:此处需要将开发板I2C引脚外接上拉电阻。


    3、软件设计

    本章教程在前面第42章基础上使用硬件I2C在DMA模式下进行主机接收从机发送实验,具体程序如下:
    iic.h文件
    1. #ifndef __IIC_H
    2. #define __IIC_H

    3. #include "ch32v10x_conf.h"

    4. /* I2C Mode Definition */
    5. #define HOST_MODE   0
    6. #define SLAVE_MODE   1

    7. /* I2C Communication Mode Selection */
    8. #define I2C_MODE   HOST_MODE
    9. //#define I2C_MODE   SLAVE_MODE

    10. /* Global define */
    11. #define Size   7
    12. #define Tize   6
    13. #define RXAdderss   0x02
    14. #define TxAdderss   0x02

    15. void IIC_Init( u32 bound, u16 address );
    16. void DMA_Tx_Init( DMA_Channel_TypeDef* DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize);
    17. void DMA_Rx_Init( DMA_Channel_TypeDef* DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize );
    18. void DMA1_Channel6_IRQHandler(void);

    19. #endif
    复制代码
    iic.h文件主要进行宏定义和函数声明;
    iic.c文件
    1. #include "iic.h"

    2. void DMA1_Channel6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

    3. /*******************************************************************************
    4. * Function Name  : IIC_Init
    5. * Description    : Initializes the IIC peripheral.
    6. * Input          : None
    7. * Return         : None
    8. *******************************************************************************/
    9. void IIC_Init( u32 bound, u16 address )
    10. {
    11.     GPIO_InitTypeDef GPIO_InitStructure;
    12.     I2C_InitTypeDef I2C_InitTSturcture;

    13.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE );
    14.     GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE); //重映射功能,PB8和PB9重映射为I2C1
    15.     RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );

    16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    18.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    19.     GPIO_Init( GPIOB, &GPIO_InitStructure );

    20.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    21.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    23.     GPIO_Init( GPIOB, &GPIO_InitStructure );

    24.     I2C_InitTSturcture.I2C_ClockSpeed = bound;    //设置I2C传输速率
    25.     I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;   //指定I2C工作模式
    26.     I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9; //指定时钟占空比
    27.     I2C_InitTSturcture.I2C_OwnAddress1 = address; //指定I2C自身设备地址
    28.     I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;  //使能或者关闭响应 (一般都是使能)
    29.     I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //指定地址的长度,可以是7位或10位
    30.     I2C_Init( I2C1, &I2C_InitTSturcture );

    31.     I2C_DMACmd( I2C1, ENABLE );

    32.     I2C_Cmd( I2C1, ENABLE );

    33. #if (I2C_MODE == HOST_MODE)
    34.     I2C_AcknowledgeConfig( I2C1, ENABLE );

    35. #endif
    36. }

    37. /*******************************************************************************
    38. * Function Name  : DMA_Tx_Init
    39. * Description    : Initializes the SPI1 DMAy Channelx configuration.
    40. * Input          : DMA_CHx:
    41. *                  ppadr: Peripheral base address.
    42. *                  memadr: Memory base address.
    43. *                  bufsize: DMA channel buffer size.
    44. * Return         : None
    45. *******************************************************************************/
    46. void DMA_Tx_Init( DMA_Channel_TypeDef* DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize)
    47. {
    48.     DMA_InitTypeDef DMA_InitStructure;
    49.     NVIC_InitTypeDef NVIC_InitStructure;

    50.     RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

    51.     DMA_DeInit(DMA_CHx);

    52.     DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;    //设置外设地址
    53.     DMA_InitStructure.DMA_MemoryBaseAddr = memadr;       //设置存储器地址
    54.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;   //设置传输方向:存储器到外设
    55.     DMA_InitStructure.DMA_BufferSize = bufsize;          //设置传输大小
    56.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;         //指定外设地址不变
    57.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                  //指定存储器地址递增
    58.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //设置外设数据单位
    59.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;          //设置存储器数据单位
    60.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;            //设置对应DMA工作模式为正常模式
    61.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  //设置DMA1通道6优先级
    62.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;             //禁止使能DMA存储器到存储器的传输方式
    63.     DMA_Init( DMA_CHx, &DMA_InitStructure );

    64.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
    65.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    66.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    67.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    68.     NVIC_Init(&NVIC_InitStructure);

    69.     DMA_ITConfig( DMA1_Channel6, DMA_IT_TC, ENABLE );
    70. }

    71. /*******************************************************************************
    72. * Function Name  : DMA_Rx_Init
    73. * Description    : Initializes the SPI1 DMAy Channelx configuration.
    74. * Input          : DMA_CHx:
    75. *                  ppadr: Peripheral base address.
    76. *                  memadr: Memory base address.
    77. *                  bufsize: DMA channel buffer size.
    78. * Return         : None
    79. *******************************************************************************/
    80. void DMA_Rx_Init( DMA_Channel_TypeDef* DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize )
    81. {
    82.     DMA_InitTypeDef DMA_InitStructure;

    83.     RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

    84.     DMA_DeInit(DMA_CHx);

    85.     DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;
    86.     DMA_InitStructure.DMA_MemoryBaseAddr = memadr;
    87.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    88.     DMA_InitStructure.DMA_BufferSize = bufsize;
    89.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    90.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    91.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    92.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    93.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    94.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    95.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    96.     DMA_Init( DMA_CHx, &DMA_InitStructure );
    97. }

    98. /*******************************************************************************
    99. * Function Name  : DMA1_Channel6_IRQHandler
    100. * Description    : This function handles DMA1 channel6 exception.
    101. * Input          : None
    102. * Output         : None
    103. * Return         : None
    104. *******************************************************************************/
    105. void DMA1_Channel6_IRQHandler(void)
    106. {
    107.     if( DMA_GetITStatus(DMA1_IT_TC6) != RESET )
    108.     {
    109.         DMA_Cmd( DMA1_Channel6, DISABLE );
    110.         DMA_ClearITPendingBit(DMA1_IT_TC6);
    111.     }
    112. }

    复制代码
    iic.c文件主要对开发板硬件I2C进行初始化配置以及发送和接收DMA初始化配置。IIC_Init函数包括硬件I2C对应GPIO引脚配置以及指定I2C外设配置,其中I2C外设配置可结合ch32v10x_i2c.c文件中I2C_Init函数以及CH32V103应用手册中I2C主模式和从模式通讯步骤进行理解。DMA_Tx_Init函数是对发送端DMA进行初始化配置,DMA_Rx_Init函数是对接收端DMA进行初始化配置。DMA1_Channel6_IRQHandler函数是DMA1通道6中断服务函数。

    当作为主机模式时,需要将指定I2C设备地址设置为主机地址,同时需要开启I2C响应设置。当作为从机模式时,需要将指定I2C设备地址设置为从机地址。

    main.c文件
    1. /********************************** (C) COPYRIGHT *******************************
    2. * File Name          : main.c
    3. * Author             : WCH
    4. * Version            : V1.0.0
    5. * Date               : 2020/04/30
    6. * Description        : Main program body.
    7. *******************************************************************************/

    8. #include "debug.h"
    9. #include "iic.h"

    10. /* Global Variable */
    11. u8 TxData[Size] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
    12. u8 RxData[Size];


    13. /*******************************************************************************
    14. * Function Name  : main
    15. * Description    : Main program.
    16. * Input          : None
    17. * Return         : None
    18. *******************************************************************************/
    19. int main(void)
    20. {

    21.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    22.     Delay_Init();
    23.     USART_Printf_Init(115200);
    24.     printf("SystemClk:%d\r\n",SystemCoreClock);

    25. #if (I2C_MODE == HOST_MODE)

    26.     printf("IIC Host mode\r\n");

    27.     u8 i=0;

    28.     //DMA初始化
    29.     DMA_Rx_Init( DMA1_Channel7, (u32)&I2C1->DATAR, (u32)RxData, Tize );

    30.     //I2C进行主机初始化配置
    31.     IIC_Init( 80000, RXAdderss);

    32.     //当I2C1处于空闲状态时,跳过此while循环,开启起始信号
    33.     while( I2C_GetFlagStatus( I2C1, I2C_FLAG_BUSY ) != RESET ); //检查是否设置了指定I2C标志

    34.     //开启I2C1通信起始信号
    35.     I2C_GenerateSTART( I2C1, ENABLE );

    36.     //当最后一个事件为I2C_EVENT_MASTER_MODE_SELECT事件时,说明选择I2C作为主机模式,跳过此while循环,进行下一步
    37.     while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );  //检查最后一个I2Cx事件是否等于作为参数传递的事件

    38.     //发送地址来选择从机设备
    39.     I2C_Send7bitAddress( I2C1, 0x02, I2C_Direction_Receiver );

    40.     //当最后一个事件为I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED事件时,说明选择I2C进行主机接收,跳过此while循环,进行下一步数据接收
    41.     while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );

    42.     //使能开启DMA1通道7进行数据接收
    43.     DMA_Cmd( DMA1_Channel7, ENABLE );

    44.     //当DMA1通道7传输完成,跳过此循环,开启下一步
    45.     while( (!DMA_GetFlagStatus(DMA1_FLAG_TC7)) );

    46.     printf( "RxData:\r\n" );

    47.     for( i=0; i<6; i++ )
    48.     {
    49.         printf( "%02x\r\n", RxData[i] );
    50.     }

    51.     //当最后一个事件为I2C_EVENT_MASTER_BYTE_RECEIVED事件时,说明接收结束,跳过此while循环,进行下一步
    52.     while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED ) );

    53.     //开启I2C通信停止信号
    54.     I2C_GenerateSTOP( I2C1, ENABLE );

    55. #elif (I2C_MODE == SLAVE_MODE)

    56.     printf("IIC Slave mode\r\n");

    57.     //DMA初始化
    58.     DMA_Tx_Init( DMA1_Channel6, (u32)&I2C1->DATAR, (u32)TxData, Tize );

    59.     //IIC初始化
    60.     IIC_Init( 80000, TxAdderss);

    61.     //当最后一个事件为I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED事件时,说明选择I2C作为从机进行数据发送,跳过此while循环,进行数据发送
    62.     while( !I2C_CheckEvent( I2C1, I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ) );

    63.     //开启DMA进行数据发送
    64.     DMA_Cmd( DMA1_Channel6, ENABLE );

    65. #endif

    66.     while(1);
    67. }

    复制代码
    main.c文件主要进行主机模式下的数据接收配置和从机模式下的数据发送配置。其中在7位地址模式下,发送的第一个字节为地址字节,头7位代表的是目标从设备地址,第8位决定了后续报文的方向,0代表是主设备写入数据到从设备,1代表是主设备向从设备读取信息。其中I2C_Send7bitAddress函数会根据第三个输入进行写入和读取的判断。


    4、下载验证

    将编译好的程序分别在主机模式和从机模式下下载到两个开发版,并将两个开发板的PB8和PB9引脚接上拉电阻然后连接起来,将两个开发板进行复位,即可进行I2C通信,主机接收开发板串口打印情况具体如下:

    CH32V CH573单片机芯片-第四十三章:CH32V103应用教程——I2C-DMA,主机接收从机发送risc-v单片机中文社区(1)


    IIC-DMA,主机接收从机发送.rar
    CH32V CH573单片机芯片-第四十三章:CH32V103应用教程——I2C-DMA,主机接收从机发送risc-v单片机中文社区(2) 42、IIC-DMA,主机接收从机发送.rar (486.4 KB, 下载次数: 11)
    链接:https://pan.baidu.com/s/1qEsRn02A9VlfbH4JdfRF4w
    提取码:jp1x
    复制这段内容后打开百度网盘手机App,操作更方便哦








    上一篇:第四十二章:CH32V103应用教程——I2C-DMA,主机发送从机接收
    下一篇:第四十四章: CH32V103应用教程——I2C-PEC,主机发送从机接收
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-26 07:39 , Processed in 0.542518 second(s), 48 queries .

    快速回复 返回顶部 返回列表