本帖最后由 codingtuzi 于 2023-4-16 20:34 编辑
【N32电机控制大赛】基于N32G455的交互式手柄钥匙
背景介绍:在工业智能制造中,机械装置越来越多地应用于车间,场矿。随之带来的操作人员权限认证与操作记录保存的需求也就日益突出。非法人员,未授权人员使用机器进行违规,危险操作;操作人员违反操作手册操作,事后追究,事故分析等问题很难清晰理清。现有权鉴方式多为传统的机械钥匙,存在易丢失,易冒用,无法追踪等风险,而对日志记录功能,基本处于空缺状态。 基于上述背景,本次项目实验设计利用国民技术加密算法库完成操作人员权限管理,利用N32G455芯片丰富的外设通讯能力操控目标设备。 方案简介:1. 由单一操控的手柄升级为可操作,可认证的手柄钥匙; 2. 使用CAN 2.0B外设与目标控制器通讯,完成目标设备的待机与实时操作; 3. 双摇杆与按键联合,保留了易操作性,便于操作人员上手使用; 4. 兼具数据记录仪功能,类似事故的“黑匣子”可用于现场回放; 5. 通过N32板载的加密算法,实现人员认证与权限管理 方案亮点:1. 在MCU中使用非对称加密方式加密密钥,不会泄露密码数据 2. 丰富的外设,如CAN 2.0和RS485物理层协议 3. 可对操作指令进行数据保存,可通过AES对称方式加密保存 4. 在强大的安全加密算法下,数据以低成本的TF卡形式保存。有效降低部署成本,让追溯更易普及 硬件设计框图硬件模块设计摇杆在对需求做市场调研时,对于机械手臂的操作,最常用的即为摇杆,操作幅度,力馈均可以较好的给操作人员带来便捷与稳定的控制。另外一种,类似于虚拟现实中的手套,体验感与科技感十足,但成本与技术门槛较高。本次设计中,采用指控摇杆的方案,成本与技术均可,体验感又保持在一定高度。 双轴摇杆采用103电位器开关实现,在设计中使用两路ADC对电压进行采集。
CAN外设对于电机控制,首选CAN通讯。养分信号的物理层协议可以屏蔽掉共模信号的干扰。CAN 2.0B的高带宽,又可以满足电机控制的实时与高精度控制。CAN控制器的Filter功能又可以最大限度的减少总线数据的影响,MCU也更专注于处理算法,专注于处理自己相关的控制信息。 RS485通讯在本次设计中,保留了低速,低成本的RS485通讯方案。此方案预留主要目的在对控制器进行固件升级,控制器配置数据更新等操作。可以将控制器连接到物联网,网关等边缘设备上。 SPI外设(SDIO外设)本次设计中有一项为日志的数据保存。对SD卡的读写物理层上驱动可以选用SDIO和SPI两种模式。考虑时间与精力上的原因,第一阶段实现SPI模式的驱动;第二阶段再实现SDIO模式。 功能 | | | SPI1 MOSI | |
| SPI1 SCLK | |
| SPI1 MISO | |
| SD select | |
|
软件模块设计本次软件架构相对简单,使用FreeRTOS嵌入式操作系统,来实现所有需求。 任务划分根据设计需求,我本次将任务划分如下: l 按键和摇杆,两者均是对电机的操作,只是采样形式不同,因此划分在同一个任务之中。以周期20ms采样,并进行滤波与去抖算法 l CAN通讯发送,在人机交互过程中,在对按键进行采集确认后,通过队列的方式接收按键键码与数值,进行封装后在CAN总线网络上发送 l CAN通讯接收,接收到设备的数据。将有效数据收集后,转存到TF卡 按键和摇杆摇杆采集的为模拟量,因此,在本次设计上,以阶段阈值的方式实现,即分为3档速度。 - void bsp_adc_init(void)
- {
- GPIO_InitType GPIO_InitStructure;
- ADC_InitType ADC_InitStructure;
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1, ENABLE);
- ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV16);
- RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8);
- /* Configure PC0 PC1 as analog input -------------------------*/
- GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure);
- /* ADC configuration ------------------------------------------------------*/
- ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT;
- ADC_InitStructure.MultiChEn = DISABLE;
- ADC_InitStructure.ContinueConvEn = DISABLE;
- ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE;
- ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R;
- ADC_InitStructure.ChsNumber = 1;
- ADC_Init(ADC1, &ADC_InitStructure);
- /* Enable ADC */
- ADC_Enable(ADC1, ENABLE);
- /*Check ADC Ready*/
- while (ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET)
- ;
- /* Start ADC calibration */
- ADC_StartCalibration(ADC1);
- /* Check the end of ADC calibration */
- while (ADC_GetCalibrationStatus(ADC1))
- ;
- }
复制代码 CAN通讯
使用CAN1外设,设置500kbps的标准帧模式 - void bsp_can_init(void)
- {
- GPIO_InitType GPIO_InitStructure;
- CAN_InitType CAN_InitStructure;
- GPIO_ConfigPinRemap(GPIO_RMP1_CAN2, ENABLE);
- /* Configure CAN1 RX pin */
- GPIO_InitStructure.Pin = GPIO_PIN_5;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
- /* Configure CAN1 TX pin */
- GPIO_InitStructure.Pin = GPIO_PIN_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
- GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
- RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_CAN2, ENABLE);
- /* CAN register init */
- CAN_DeInit(CAN2);
- /* Struct init*/
- CAN_InitStruct(&CAN_InitStructure);
- /* CAN cell init */
- CAN_InitStructure.TTCM = DISABLE;
- CAN_InitStructure.ABOM = DISABLE;
- CAN_InitStructure.AWKUM = DISABLE;
- CAN_InitStructure.NART = DISABLE;
- CAN_InitStructure.RFLM = DISABLE;
- CAN_InitStructure.TXFP = ENABLE;
- CAN_InitStructure.OperatingMode = OPERATINGMODE;
- CAN_InitStructure.RSJW = CAN_BIT_RSJW;
- CAN_InitStructure.TBS1 = CAN_BIT_BS1;
- CAN_InitStructure.TBS2 = CAN_BIT_BS2;
- CAN_InitStructure.BaudRatePrescaler = CAN_BAUDRATEPRESCALER; // 500K
- /*Initializes the CAN */
- CAN_Init(CAN1, &CAN_InitStructure);
- CAN_Filter_Init();
- CAN_NVIC_Config();
- }
复制代码 RS485通讯- void bsp_usart_init(void)
- {
- USART_InitType USART_InitStructure;
- GPIO_InitType GPIO_InitStructure;
- NVIC_InitType NVIC_InitStructure;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
- uart_rx.length = 0;
- uart_rx.state = rx_state_idle;
- /* Enable the USARTy Interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- // RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_AFIO, ENABLE);
- /* Enable USARTy and USARTz Clock */
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1, ENABLE);
- /* Configure USARTx Tx as alternate function push-pull */
- GPIO_InitStructure.Pin = GPIO_PIN_9;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- /* Configure USARTx Rx as input floating */
- GPIO_InitStructure.Pin = GPIO_PIN_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- /* USARTy and USARTz configuration ------------------------------------------------------*/
- USART_InitStructure.BaudRate = 9600;
- USART_InitStructure.WordLength = USART_WL_8B;
- USART_InitStructure.StopBits = USART_STPB_1;
- USART_InitStructure.Parity = USART_PE_NO;
- USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
- USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
- // USART_ConfigInt(USART1, USART_INT_RXDNE, ENABLE);
- // USART_ConfigInt(USART1, USART_INT_IDLEF, ENABLE);
- /* Configure USARTx */
- USART_Init(USART1, &USART_InitStructure);
- /* Enable the USARTx */
- USART_Enable(USART1, ENABLE);
- }
复制代码 SPI通讯
SD卡操作状态流转图:
- void bsp_spi_init(void)
- {
- GPIO_InitType GPIO_InitStructure;
- SPI_InitType SPI_InitStructure;
- /* PCLK2 = HCLK/2 */
- RCC_ConfigPclk2(RCC_HCLK_DIV2);
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_SPI1 | RCC_APB2_PERIPH_AFIO, ENABLE);
- /* Configure SPIy pins: SCK, MISO and MOSI ---------------------------------*/
- GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.Pin = GPIO_PIN_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- /* SPI1 Config -------------------------------------------------------------*/
- SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
- SPI_InitStructure.SpiMode = SPI_MODE_MASTER;
- SPI_InitStructure.DataLen = SPI_DATA_SIZE_8BITS;
- SPI_InitStructure.CLKPOL = SPI_CLKPOL_HIGH;
- SPI_InitStructure.CLKPHA = SPI_CLKPHA_SECOND_EDGE;
- SPI_InitStructure.NSS = SPI_NSS_SOFT;
- SPI_InitStructure.BaudRatePres = SPI_BR_PRESCALER_256;
- SPI_InitStructure.FirstBit = SPI_FB_MSB;
- SPI_InitStructure.CRCPoly = 7;
- SPI_Init(SPI1, &SPI_InitStructure);
- /* Enable SPIy */
- SPI_Enable(SPI1, ENABLE);
- }
复制代码 实物照片
|