OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6970|回复: 15

stm32f103mini 用端口PA8输出pwm控制继电器闭合,继电器始终闭合,求帮助

[复制链接]

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
发表于 2020-4-29 10:55:25 | 显示全部楼层 |阅读模式
/*
        主函数
        TIM3        用于按键扫描与时间标志位的更新
        TIM1  用于输出PWM控制电热丝加热时间
       
        PA0          DS18B20
        PA8                连接继电器/同时也是DS0
*/
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "ds18b20.h"
#include "pid.h"
#include "timer.h"
#include "keyboard.h"
#include "pwm.h"
#include "heat.h"

unsigned int TEMP;                                                //储存到小数一位的实际实时温度
unsigned int SETTEMP;                                        //储存到小数一位的实际设置温度
unsigned int PWM=2500;
u8 flag100ms=0;

void KeyAction(unsigned char key);
void ShowTemp(void);
void ShowSetTemp(void);
void ShowPWM(void);

int main(void)
{
        unsigned char flag500ms=0;
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //设置系统中断优先级分组2
        delay_init();                                                                                 //初始化延时函数
        uart_init(9600);                                                                        //初始化串口波特率为115200
        LED_Init();                                                                                        //初始化LED
        LCD_Init();
        TIM3_Int_Init(10-1,8400-1);                        //分频系数8400 计数频率10KHz 计数到10溢出 每1Ms产生中断
        TIM1_PWM_Init(10000-1,8400-1);
        KEY_Init();
        PID_Init();
       
        POINT_COLOR=RED;//设置字体为红色
        LCD_ShowString(30,10,200,16,16,"STM32F1 MINI");       
        LCD_ShowString(30,30,200,16,16,"2020/4/27");
       
        while(DS18B20_Init())                                                                        //DS18B20初始化       
        {
                LCD_ShowString(30,50,200,16,16,"SENSOR Error");
                delay_ms(200);
                LCD_Fill(30,50,239,130+16,WHITE);
                delay_ms(200);
        }
        LCD_ShowString(30,50,200,16,16,"SENSOR  OK");
       
        POINT_COLOR=BLUE;                                                                                //设置字体为蓝色
        LCD_ShowString(30,70,200,16,16,"TEMP:   . C");
        LCD_ShowString(30,90,200,16,16,"SET :   . C");
        LCD_ShowString(30,110,200,16,16,"WM :     /9999");
        SETTEMP=250;                                                                                        //设定目标温度
        LCD_DrawLine(0,900-(SETTEMP/2),300,900-(SETTEMP/2));
        ShowSetTemp();
        ShowPWM();
        TIM_SetCompare1(TIM1,PWM);                                                                //最大为10000控制占空比
        while(1)
        {
                if(flag100ms)                                                                                //每100ms更新一次实时温度
                {
                        flag100ms=0;
                       
                        flag500ms++;
                        if(flag500ms==5)
                        {
                                flag500ms=0;
                                ShowTemp();                                                                        //500ms测量一次温度
                                PWM=PID_realize();
                                TIM_SetCompare1(TIM1,PWM);
                                ShowPWM();
                        }
                }
                 delay_ms(10);
        }
}

/****************************************************************************************/
void ShowSetTemp(void)
{
        LCD_ShowNum(30+40+8,90,SETTEMP/10,2,16);        //显示正数部分            
        LCD_ShowNum(30+40+32,90,SETTEMP%10,1,16);        //显示小数部分
}

void ShowPWM(void)
{
        LCD_ShowNum(30+40+8,110,PWM,4,16);
}

void ShowTemp(void)
{
        static int x=0;
        short temperature;  
{                                                                          
                        temperature=DS18B20_Get_Temp();       
                        TEMP=temperature;                                       
               
        LCD_ShowNum(30+40+8,70,temperature/10,2,16);        //显示正数部分            
        LCD_ShowNum(30+40+32,70,temperature%10,1,16);        //显示小数部分
       
        //给当前温度打点
        x++;if(x>=300)x=0;
        LCD_DrawPoint(x,900-(TEMP/2));
  }
}
void KeyAction(unsigned char key)
{
        switch(key)
        {
                case 1ED0=0;break;
                case 2ED0=1;break;
                case 3ED0=~LED0;break;
                case 4ED0=~LED0;break;
                default:break;
        }
}
/*
        pid函数
*/
#include "pid.h"
#include "lcd.h"

extern unsigned int TEMP;                                                //储存到小数一位的实际实时温度
extern unsigned int SETTEMP;                                        //储存到小数一位的实际设置温度

struct PID pid;

void PID_Init(void)                                        //因为有储存,因此用ReadPID()代替
{
        pid.Set=SETTEMP;
        pid.Actual=TEMP;
        pid.err=0;
        pid.err_last=0;                                                                                                                                                                                                   

        pid.Kp=50;                                                //实际为除1倍
        pid.Ki=100;                                                //实际为除1000倍
        pid.Kd=350;                                                //实际为除1倍
        pid.Kout=900;                                                //偏移值
        pid.voltage=0;
        pid.integral=0;
       
        LCD_ShowNum(170,10,pid.Kp,3,16);
        LCD_ShowNum(170,30,pid.Ki,3,16);
        LCD_ShowNum(170,50,pid.Kd,3,16);
        LCD_ShowNum(170,70,pid.Kout,3,16);
}

int PID_realize(void)
{
        int t;
       
        pid.Set      = SETTEMP;                                        //设定值
        pid.Actual   = TEMP;                                        //实际值
        pid.err      = pid.Set - pid.Actual;        //差值
       

        pid.integral = pid.integral + pid.err;
        //LCD_ShowNum(30+60+12,240,pid.integral,6,24);

        pid.voltage = pid.Kp*pid.err                                                                //设定值与实际的偏差
                                + pid.Ki*pid.integral/1000                                                //历史累计偏差
                                + pid.Kd*(pid.err-pid.err_last)                                        //本次偏差与上次偏差比较
                                + pid.Kout;                                                                                //最终计算值
       
        pid.err_last = pid.err;
       
        t=pid.voltage;
       
        if(t>9999)                t=9998;
        else if(t<0)        t=2;
        return t;
}

/*
        pwm函数
*/

#include "pwm.h"
#include "led.h"
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 使能TIM1时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟
                                                                                    

   //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);       
       
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         80K
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIM1的时间基数单位
        TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE ); //③允许更新中断


        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        //TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

  //TIM_CtrlPWMOutputs(TIM1,ENABLE);        //MOE 主输出使能       
        TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1预装载使能         
        TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
        TIM_Cmd(TIM1, ENABLE);  //使能TIM1


}











正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 11:11:11 | 显示全部楼层
回复 支持 反对

使用道具 举报

1

主题

882

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3071
金钱
3071
注册时间
2018-2-7
在线时间
285 小时
发表于 2020-4-29 13:10:11 | 显示全部楼层

回帖奖励 +1 金钱

继电器的吸合电流多大,你的继电器驱动电流够吗?
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 13:42:10 | 显示全部楼层
够的,因为用原子给的pwm例程,PA8引脚可以控制继电器的闭合状态。
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 13:42:30 | 显示全部楼层
HXYDJ 发表于 2020-4-29 13:10
继电器的吸合电流多大,你的继电器驱动电流够吗?


够的,因为用原子给的pwm例程,PA8引脚可以控制继电器的闭合状态。
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-4-29 13:43:19 | 显示全部楼层
两种方案
1.串口1放到pwm后面初始化
2.pwm定时器用的的结构体用之前先用库函数设置成默认值
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 14:56:53 | 显示全部楼层
nashui_sx 发表于 2020-4-29 13:43
两种方案
1.串口1放到pwm后面初始化
2.pwm定时器用的的结构体用之前先用库函数设置成默认值

方案一:ds0熄灭没有反映(原先常亮)
方案二:没怎么理解,希望大佬说仔细一点,谢谢
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-4-29 15:27:29 | 显示全部楼层
本帖最后由 nashui_sx 于 2020-4-29 15:29 编辑
Herxinsasa 发表于 2020-4-29 14:56
方案一:ds0熄灭没有反映(原先常亮)
方案二:没怎么理解,希望大佬说仔细一点,谢谢

方案1 只适合串口这一类冲突的不好的解决方案,不过肯定可以 ,你检查别的问题

2 下面这三行代码 你定义了那个变量  定义完就执行下,理论上所有stm32带的结构体都要这么用,也都有相应的默认值函数
不调用默认值的原因就是有些参数的默认值不是0.你又没初赋值

        TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);  //设置缺省值,这一步最好加上防止放到串口初始化后出问题
        TIM_OCStructInit(&TIM_OCInitStructure);        //设置缺省值,这一步最好加上防止放到串口初始化后出问题
        TIM_ICStructInit(&TIM_ICInitStructure);        //设置缺省值,这一步最好加上防止放到串口初始化后出问题
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 15:50:09 | 显示全部楼层
代码是从f4移植到f103mini的其他都没有问题(TIM14改为TIM1),探索者上运行没有问题,mini上PA8无PWM输出
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 15:56:50 | 显示全部楼层
nashui_sx 发表于 2020-4-29 15:27
方案1 只适合串口这一类冲突的不好的解决方案,不过肯定可以 ,你检查别的问题

2 下面这三行代码 你定 ...

一二两句都有,点三个输入没用到也要初始化吗,您说的没附初值的变量是哪个哈,实在麻烦你了
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-4-29 15:58:16 | 显示全部楼层
Herxinsasa 发表于 2020-4-29 15:56
一二两句都有,点三个输入没用到也要初始化吗,您说的没附初值的变量是哪个哈,实在麻烦你了

那是列举 用哪个 对应用哪个就好了 没用屏蔽了就行了  别的can  等等都一样急着养成习惯就好了
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 16:06:08 | 显示全部楼层
nashui_sx 发表于 2020-4-29 15:58
那是列举 用哪个 对应用哪个就好了 没用屏蔽了就行了  别的can  等等都一样急着养成习惯就好了

pwm用的是原子的库函数应该都齐的吧,我有点笨还是没理解您说的问题在哪,&#128557;
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 16:08:40 | 显示全部楼层
这是代码...

温度跟踪系统.zip

4.43 MB, 下载次数: 24

回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-4-29 16:32:55 | 显示全部楼层
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2020-4-6
在线时间
12 小时
 楼主| 发表于 2020-4-29 16:41:39 | 显示全部楼层

哇实在是太感谢了
回复 支持 反对

使用道具 举报

7

主题

105

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1026
金钱
1026
注册时间
2016-1-28
在线时间
134 小时
发表于 2022-9-6 17:08:17 | 显示全部楼层
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-26 04:06

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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