📈 算法与建模 | 专注PLC、单片机毕业设计
✨ 擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅ 专业定制毕业设计
✅ 具体问题可以私信或查看文章底部二维码
针对牙科治疗椅的多自由度调节、功能集成控制、安全防护等需求进行设计,实现治疗椅的升降、靠背角度调节、头枕调节、脚踏控制以及联动设备(如牙科灯、吸唾器)的一体化控制。硬件层面,主控单片机选用具备多路 PWM 输出和 AD 采集功能的型号,满足电机调速和模拟信号采集需求;动力模块采用直流减速电机驱动治疗椅的升降和角度调节,电机驱动单元选用 H 桥驱动芯片,单片机通过 PWM 信号调节电机转速和转向,实现治疗椅位置的精准控制;输入模块包含医护人员手持控制面板、患者脚踏开关,控制面板采用薄膜按键,设置上升、下降、靠背前倾、靠背后仰、头枕调节、急停等功能按键,按键信号经防抖电路后接入单片机 GPIO 口,脚踏开关设置简单的启停和模式切换功能,方便患者配合治疗;位置检测模块采用霍尔传感器和电位器组合,霍尔传感器安装在电机转轴处,记录电机转动圈数以计算治疗椅移动距离,电位器则实时反馈靠背、头枕的角度值,模拟信号经 AD 转换后传入单片机,单片机通过闭环控制算法,将实际位置与目标位置对比,调整电机运行状态,实现位置精准定位。
系统的联动控制设计是核心,单片机集成对牙科灯、吸唾器、漱口水供水泵等外设的控制接口,当治疗椅调节至预设治疗角度(如仰卧、半卧)时,单片机自动触发对应外设的工作模式,例如仰卧模式下牙科灯自动开启并调节至预设亮度,吸唾器进入待机状态;同时设计模式存储功能,单片机可记录常用的治疗体位参数(如升降高度、靠背角度),医护人员可通过控制面板一键调用预设体位,无需重复调节,提升诊疗效率。安全防护设计是重点,系统设置多重保护机制:急停按键接入单片机外部中断,触发后立即切断电机驱动电源,停止所有动作;电流检测模块实时监测电机工作电流,当电流超过阈值(如卡阻导致过载)时,单片机立即停止电机输出并触发报警;限位开关安装在治疗椅各运动机构的极限位置,当运动至极限位置时,限位开关触发,单片机切断对应电机的驱动信号,防止机械结构损坏;此外,系统设计压力传感器,安装在治疗椅坐垫和头枕处,当检测到患者异常移动导致压力突变时,暂停当前调节动作,待医护人员确认后恢复,避免夹伤等安全事故。
软件层面,系统采用分层设计架构,底层为硬件驱动层,包含电机驱动、按键扫描、传感器采集、外设控制等子程序,实现对硬件的基础操作;中间层为控制算法层,包含位置闭环控制、模式存储与调用、联动逻辑控制等子程序,其中位置闭环控制算法通过对比目标位置和传感器反馈的实际位置,动态调整 PWM 占空比,实现治疗椅的平稳调节和精准定位;上层为交互层,负责控制面板的按键解析、状态显示和报警提示,单片机驱动 LCD 显示屏实时显示治疗椅当前的高度、靠背角度、工作模式以及外设状态,当出现过载、限位触发、急停等异常情况时,蜂鸣器和 LED 报警灯启动,同时显示屏显示故障代码,方便医护人员排查。系统还设计了手动 / 自动模式切换功能,自动模式下按预设程序完成体位调节,手动模式下医护人员可通过按键精细调节各部位位置,满足不同诊疗场景的需求。调试阶段,重点对电机调速曲线、位置控制精度、联动逻辑响应速度进行优化,通过多次实测调整 PWM 参数和闭环控制的比例系数,使治疗椅调节过程平稳无顿挫,位置误差控制在毫米级,同时验证安全保护机制的可靠性,确保各保护触发条件准确、响应及时。
#include "stm32f10x.h" #include "stdio.h" #include "string.h" #define MOTOR_UP_DOWN_PIN GPIO_Pin_0 #define MOTOR_BACK_PIN GPIO_Pin_1 #define MOTOR_HEAD_PIN GPIO_Pin_2 #define KEY_UP_PIN GPIO_Pin_3 #define KEY_DOWN_PIN GPIO_Pin_4 #define KEY_BACK_FWD_PIN GPIO_Pin_5 #define KEY_BACK_BCK_PIN GPIO_Pin_6 #define KEY_HEAD_PIN GPIO_Pin_7 #define KEY_EMERGENCY_PIN GPIO_Pin_8 #define KEY_MODE_PIN GPIO_Pin_9 GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; uint16_t adc_value[3]; uint16_t height_pos = 0; uint16_t back_angle = 0; uint16_t head_angle = 0; uint8_t emergency_flag = 0; uint8_t auto_mode = 0; uint8_t preset_mode[3][3] = {{500, 120, 30}, {600, 90, 20}, {450, 150, 40}}; uint8_t preset_index = 0; void RCC_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); } void GPIO_Configuration(void) { GPIO_InitStructure.GPIO_Pin = MOTOR_UP_DOWN_PIN | MOTOR_BACK_PIN | MOTOR_HEAD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN | KEY_DOWN_PIN | KEY_BACK_FWD_PIN | KEY_BACK_BCK_PIN | KEY_HEAD_PIN | KEY_EMERGENCY_PIN | KEY_MODE_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); } void TIM_Configuration(void) { TIM_TimeBaseStructure.TIM_Period = 999; TIM_TimeBaseStructure.TIM_Prescaler = 71; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_OC2Init(TIM2, &TIM_OCInitStructure); TIM_OC3Init(TIM2, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_Cmd(TIM2, ENABLE); } void ADC_Configuration(void) { ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 3; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); } void DMA_Configuration(void) { DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_value; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 3; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); } void ReadSensorData(void) { height_pos = adc_value[0]; back_angle = adc_value[1]; head_angle = adc_value[2]; } void MotorControl(uint8_t motor, uint16_t pwm) { if(emergency_flag) { TIM_SetCompare1(TIM2, 0); TIM_SetCompare2(TIM2, 0); TIM_SetCompare3(TIM2, 0); return; } switch(motor) { case 0: TIM_SetCompare1(TIM2, pwm); break; case 1: TIM_SetCompare2(TIM2, pwm); break; case 2: TIM_SetCompare3(TIM2, pwm); break; default: break; } } void KeyScan(void) { if(GPIO_ReadInputDataBit(GPIOB, KEY_EMERGENCY_PIN) == 0) { emergency_flag = 1; return; } else { emergency_flag = 0; } if(GPIO_ReadInputDataBit(GPIOB, KEY_MODE_PIN) == 0) { auto_mode = !auto_mode; while(GPIO_ReadInputDataBit(GPIOB, KEY_MODE_PIN) == 0); } if(auto_mode) { if(GPIO_ReadInputDataBit(GPIOB, KEY_UP_PIN) == 0) { preset_index = (preset_index + 1) % 3; height_pos = preset_mode[preset_index][0]; back_angle = preset_mode[preset_index][1]; head_angle = preset_mode[preset_index][2]; while(GPIO_ReadInputDataBit(GPIOB, KEY_UP_PIN) == 0); } } else { if(GPIO_ReadInputDataBit(GPIOB, KEY_UP_PIN) == 0) { MotorControl(0, 500); } else if(GPIO_ReadInputDataBit(GPIOB, KEY_DOWN_PIN) == 0) { MotorControl(0, 300); } else { MotorControl(0, 0); } if(GPIO_ReadInputDataBit(GPIOB, KEY_BACK_FWD_PIN) == 0) { MotorControl(1, 400); } else if(GPIO_ReadInputDataBit(GPIOB, KEY_BACK_BCK_PIN) == 0) { MotorControl(1, 200); } else { MotorControl(1, 0); } if(GPIO_ReadInputDataBit(GPIOB, KEY_HEAD_PIN) == 0) { MotorControl(2, 350); } else { MotorControl(2, 0); } } } int main(void) { RCC_Configuration(); GPIO_Configuration(); TIM_Configuration(); ADC_Configuration(); DMA_Configuration(); while(1) { ReadSensorData(); KeyScan(); if(auto_mode) { if(height_pos < preset_mode[preset_index][0]) { MotorControl(0, 450); } else if(height_pos > preset_mode[preset_index][0]) { MotorControl(0, 250); } else { MotorControl(0, 0); } if(back_angle < preset_mode[preset_index][1]) { MotorControl(1, 380); } else if(back_angle > preset_mode[preset_index][1]) { MotorControl(1, 220); } else { MotorControl(1, 0); } if(head_angle < preset_mode[preset_index][2]) { MotorControl(2, 320); } else if(head_angle > preset_mode[preset_index][2]) { MotorControl(2, 180); } else { MotorControl(2, 0); } } for(int i=0;i<1000;i++); } }如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇