找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

PIC单片机输出不了占空比50%的方波——帮扶一把学单片机的60后

查看数: 7475 | 评论数: 53 | 收藏 1
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2021-11-24 11:18

正文摘要:

自我介绍下:60后从业模电,自封工程师,动手能力强。学单片机历程30年,学级仍是未入门的学前班。所以各位看官都是我的老师,各位的每句话都能使我进步!期望大家都出一份正能量!废话不说入正题:PIC12F683单片机 ...

回复

ID:401564 发表于 2021-12-2 18:54
xxll 发表于 2021-12-2 17:58
我不说过我是个门外汉吗!与我也不会呀

门外汉不是理由
与或非编程基础类知道,不管是你半路出家还是科班出身,不管你专业人士还业余爱好,也不管你是长期爱好还是一时性起
这基础知道是肯定要学的,如果不想学,那就不要搞单片机了
不是打击你,而是没有基础的话,那这单片机玩起来实在太累了,还浪费时间
从你这个问题就可以看出来了,如果当初,你多花一个小时的时间去看一下端口设置,那你就不会在这50%占空比上面花那么多的时间和精力
个人感觉,很多时候,一个自己几天甚至半个月都搞不定的东西,很有可能只是一个简单的东西而已,只是自己没有严谨认真的去看相关的资料而已
我之前就经常碰到这样的问题,一个小小的东西,搞几天都搞不好,怎么找都找不到问题,最后干脆之前的代码都不要,从头再看资料,一步一步的来,一下子就发现问题了,而且,不过是一个很基础很简的问题而已,只是自己老是钻牛角尖而已
所以,基础很重要,不管你多大年纪,不管你是出什么目的学单片机,多看一下基础,不会有坏处
ID:139866 发表于 2021-12-2 18:04
xxll 发表于 2021-12-2 17:44
你好,这个或运算是如何实现的,我不懂啦。如0x06=0b00000110,若原GPIO=0b00000010或运算后它不还是0b000 ...

GPIO |= 0x06;//这个1,2位输出高电平,不改变其他位
GPIO &= 0XF9;//这个1,2位输出低电平,同样不改变其他位
ID:624769 发表于 2021-12-2 18:03
xxll 发表于 2021-12-2 17:44
你好,这个或运算是如何实现的,我不懂啦。如0x06=0b00000110,若原GPIO=0b00000010或运算后它不还是0b000 ...

抱歉,是我的锅,没复验就发了。
应该是
gpio ^= 0x06;   与或计算,即1变0,0变1。手机发帖排版大小写就不修改了。
ID:27513 发表于 2021-12-2 17:58
Y_G_G 发表于 2021-12-2 17:49
GPIO |= 0x06;
这个是不行的,或指令不能输出低电平的
你自己也要思考一下的嘛

我不说过我是个门外汉吗!与我也不会呀
ID:624769 发表于 2021-12-2 17:56
Y_G_G 发表于 2021-12-2 17:49
GPIO |= 0x06;
这个是不行的,或指令不能输出低电平的
你自己也要思考一下的嘛

打错了gpio^=0x06
ID:401564 发表于 2021-12-2 17:49
xxll 发表于 2021-12-2 17:44
你好,这个或运算是如何实现的,我不懂啦。如0x06=0b00000110,若原GPIO=0b00000010或运算后它不还是0b000 ...

GPIO |= 0x06;
这个是不行的,或指令不能输出低电平的
你自己也要思考一下的嘛
肯定是要用&的嘛
ID:27513 发表于 2021-12-2 17:44
188610329 发表于 2021-12-2 13:40
老哥,如果你要实现 产品副本.jpg 那样的波形的话,你改写端口的指令必须修改。

void interrupt isr(voi ...

你好,这个或运算是如何实现的,我不懂啦。如0x06=0b00000110,若原GPIO=0b00000010或运算后它不还是0b00000110吗?
ID:624769 发表于 2021-12-2 13:40
老哥,如果你要实现 产品副本.jpg 那样的波形的话,你改写端口的指令必须修改。

void interrupt isr(void)   //中断子程序
{
TMR0=224;
T0IF=0;
GPIO |= 0x06;      // 要用字节改写 GPIO总线, 而不是用位改写 IO
}
ID:401564 发表于 2021-12-2 12:03
xxll 发表于 2021-12-2 11:43
不是同一端口,原来是GP0与GP1,现在改为GP1与GP2了,其实道理是一样的

GPIO就是一个端口的好不好,直接赋值GPIO端口应该就可以得到你要波形了{
                       GPIO=0x01;//GP0   GP1输出,自己也可以改其它的IO,如果不想影响其它IO,可以用&
               
                        ON=0;
                        }

                else
                        {
                       
                        GPIO=0x02;
                        ON=1;                       
                        }
ID:27513 发表于 2021-12-2 11:43
本帖最后由 xxll 于 2021-12-2 12:03 编辑
Y_G_G 发表于 2021-12-2 11:26
这GP1和GP0是在同一个端口的吗?没有看数据手册,不知道
不同端口的话,那是要两条指令,那是肯定要有延时的 ...

不是同一端口,原来是GP0与GP1,现在改为GP1与GP2了,其实道理是一样的厅
是我理解错了是同一个端口寄存器,因为只有8个引脚的单片机。
ID:401564 发表于 2021-12-2 11:26
xxll 发表于 2021-12-2 11:05
这个波形图是中断子程序
void interrupt isr(void)   //中断子程序
{

这GP1和GP0是在同一个端口的吗?没有看数据手册,不知道
不同端口的话,那是要两条指令,那是肯定要有延时的
如果是同一个端口,那就是一条指令就行了if(ON)
                        {
                       PORTD=0x01;//假设是RD端口输出
               
                        ON=0;
                        }

                else
                        {
                       
                        PORTD=0x02;
                        ON=1;                       
                        }
ID:27513 发表于 2021-12-2 08:45
taotie 发表于 2021-11-28 00:10
相差无几
时钟8Mhz,标志判断的内容由死循环转到中断子程序中。
初值设置为225    ...

你的程序我也测试了,示波器上的波形不稳定,一会正常一会跳变成窄宽不等的波形。还有你这种方式我个人觉得不妥,如果在主程序中加入按键扫描和指示灯闪烁,这种方式就更无法正常输出频率稳定的方波了。你认为呢?
ID:342822 发表于 2021-11-28 00:10
本帖最后由 taotie 于 2021-11-29 14:49 编辑



相差无几
时钟8Mhz,标志判断的内容由死循环转到中断子程序中。
初值设置为225     方波频率=20000hz


* Created:   周六 11月 27 2021
* Processor: PIC12F683
* Compiler:  HI-TECH C for PIC10/12/16
*/

#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO==0b00000000;

        }
void timer0_init(void) //定时器0初始化使用系统默认时钟4M fosc/4 所以计数周期为1us
        {
                T0CS=0;    //timer0工作于定时器方式
                PSA=1;     //timer0不分频
                T0IF=0;    //清timer0中断标志
                TMR0=225; /*置初值 20KHz的半个周期为25us*/
                T0IE=1;    //timer0中断允许
                GIE=1;     //开全局中断
        }


void main(void)          //主程序
        {

                IO_init();         //引脚初始化函数
                timer0_init();     //定时器0初始化函数

                while(1)    //死循环
         {      

}
        }

void interrupt isr(void)   //中断子程序
        {

               //T0IF=0;    //清中断标志
                TMR0=225; //定时器0置初值25us
{
                if(flag)
         {
                      GPIO=0B00000001;

                }
                         else
                     {
                         GPIO=0B00000010;

                      }

                        T0IF=0;

                }

                             flag = !flag;                       

        }  

ID:342822 发表于 2021-11-27 22:34
虽然占空比没达到百分之50,但已经是互补方波了



/* Main.c file generated by New Project wizard
*
* Created:   周六 11月 27 2021
* Processor: PIC12F683
* Compiler:  HI-TECH C for PIC10/12/16
*/

#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO==0b00000000;

        }
void timer0_init(void) //定时器0初始化使用系统默认时钟4M fosc/4 所以计数周期为1us
        {
                T0CS=0;    //timer0工作于定时器方式
                PSA=1;     //timer0不分频
                T0IF=0;    //清timer0中断标志
                TMR0=224; /*置初值 20KHz的半个周期为25us*/
                T0IE=1;    //timer0中断允许
                GIE=1;     //开全局中断
        }


void main(void)          //主程序
        {

                IO_init();         //引脚初始化函数
                timer0_init();     //定时器0初始化函数

                while(1)    //死循环
                {
                               if(flag)
                                        {
                                                GPIO=0B00000001;

                                        }
                                        else
                                        {
                                                 GPIO=0B00000010;

                                        }



                }

        }

void interrupt isr(void)   //中断子程序
        {

                T0IF=0;    //清中断标志
                                TMR0=224; //定时器0置初值25us

                                flag = !flag;

        }  

ID:624769 发表于 2021-11-27 20:17
xxll 发表于 2021-11-27 09:08
ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO

从你发的手册上看,

ANSEL 控制引脚是模拟输入,还是数字输出。
如果 有 位置1则为模拟输入,如果该位置0则为数字输出。
手册上看,上电后 ANSEL 的初值不为0。
并且,手册上还说,上电后端口初始化 ANSEL 需要 置 0 复位。
另外,和GPIO有关的寄存器,总共有11个,

此表中,没有打阴影的部分,都是会影响GPIO的输出的设置。
通过此表也能看到,ANSEL 不设置0的话,GPIO0~GPIO3 默认为模拟输入。
ID:27513 发表于 2021-11-27 19:56
Y_G_G 发表于 2021-11-26 14:36
还在折腾这个?
TMR0=0xE0(224),定时器就是256-224=32
如果你是用4MHZ时钟,那么,定时器的中断时间是不低于 ...

关于这里的TMRO=224是因为时钟是8M时设的值,(256-224)*0.5=16us在8M时钟时CPU执行中断大约耗费9us (后面也证实了),16+9=25
ID:401564 发表于 2021-11-27 12:25
xxll 发表于 2021-11-27 09:08
ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO

还要添加一条:
CMCON0=0x07;
ID:401564 发表于 2021-11-27 12:00
xxll 发表于 2021-11-27 09:08
ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO

你试过增加ANSEL=0x00;这语句没有?
ANSEL 是要先清除的!
ID:27513 发表于 2021-11-27 09:08
188610329 发表于 2021-11-26 21:34
老哥, 你说…… ,会不会是因为:

ANSEL = 0; 这句没写的关系啊?

ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO
ID:624769 发表于 2021-11-26 21:34
老哥, 你说…… ,会不会是因为:

ANSEL = 0; 这句没写的关系啊?

我琢磨了很久,你在顶楼说的,删除了GP1 = !GP0;  就没输出了, 你觉得不应该,我也觉得不应该,所以,我在想,是不是一开始咱们就没找对方向? 其实就是端口的初始化没有做好? 所以没有输出?
ID:27513 发表于 2021-11-26 20:44
18434225 发表于 2021-11-26 18:45
从你这个图可以看出,那个脉冲是你每次进去之后GP0=~GP0取反的结果,后面变低是因为你又GP1=!GP0,使其变低 ...

正半周25us+负半周25us,总周期是50us哪来的40KHZ,这个单片机20KHZ都可能做不督到,还40K
双脚输出互补的方波如果拿来驱动逆变半桥,GP1=GP0想想是什么后果?再都为了试验,前面说过都试过了,没有变化,是一样的。这东西折腾很久了,不是我执着,论个所以然,早就放弃了……
ID:401564 发表于 2021-11-26 18:54
xxll 发表于 2021-11-26 18:19
这位老师好!我把你的方案和数据测试结果汇报给你:时钟4M时,GP0正脉宽0.8us负脉宽75.2us频率13KHz;
GP1 ...

你把完整的代码上传一下
GP0和GP1是一样的调整,在时间上应该是一致的,没有理由只有一个行,一个不行的,要么就都不行,要么就都行
你也可以自己调试一下的呀,把GP1代码删除,或者把GP0换成其它的端口试一下
void interrupt isr(void)   //中断子程序
                {
                        
                        T0IF=0;    //清中断标志
                        if(ON)
                             {
                               GP0=1;
                                GP1=0;
                               ON=0;
                             }   
                       else
                             {
                               GP0=0;
                                GP1=1;
                               ON=1;
                             }   
TMR0=240; //定时器0置初值,先看结果,这设置放后面                           
                }
ID:27513 发表于 2021-11-26 18:19
Y_G_G 发表于 2021-11-26 14:36
还在折腾这个?
TMR0=0xE0(224),定时器就是256-224=32
如果你是用4MHZ时钟,那么,定时器的中断时间是不低于 ...

这位老师好!我把你的方案和数据测试结果汇报给你:时钟4M时,GP0正脉宽0.8us负脉宽75.2us频率13KHz;
GP1正脉宽38.8us,负脉宽37.6us,频率13KHZ

时钟设置成8M时:GP0正脉宽0.5us(500ns),负脉宽示波器没报,频率26.3KHZ;
GP1正脉宽19.4us,负脉宽18.6us,频率26.3KHz
老师从这二种时钟数据看,只有GP1正负脉冲占空比能接近50%,而GP0正脉冲太窄,你看如何解决?
ID:401564 发表于 2021-11-26 14:36
还在折腾这个?
TMR0=0xE0(224),定时器就是256-224=32
如果你是用4MHZ时钟,那么,定时器的中断时间是不低于32uS的,你这还怎么达到?20KHZ的输出?
TMR0=0xE0; /*置初值 20KHz的半个周期为25us*/..........这是怎么算出来的?
而且,PIC是没有堆栈指令的,编译器可能还要加几条保存W和其它会改变的文件寄存器的指令
这样一来,你这个是肯定不会有20KHZ的频率的
而且,在中断程序中,尽量少用变量计算,没有用过PIC的C,不知道PIC有没有位,如果有位,就用位来判断,定时器设定要高于20KHZ,TMR0的值要大于0xe7
先声明一个位
void interrupt isr(void)   //中断子程序
                {
                        TMR0=240; //定时器0置初值,先看结果,再慢慢调节
                        T0IF=0;    //清中断标志
                        if(ON)
                             {
                               GP0=1;
                                GP1=0;
                               ON=0;
                             }   
                       else
                             {
                               GP0=0;
                                GP1=1;
                               ON=1;
                             }                                
                }

ID:27513 发表于 2021-11-26 09:41
xqleft 发表于 2021-11-26 09:20
我现在用得单片机刚好是PIC架构得。我看了半天不知道理解对不对。你想GP1输出的正占空比,GP0输出的正占空 ...

我要的就是一个引脚上正50%,负50%就这样简单,要求是用定时器0实现,频率20KHZ
ID:342822 发表于 2021-11-26 09:38
lids 发表于 2021-11-25 09:29
仿真试了下,一路方波正常,两路波形就乱了
#include

一路方波正常很好~~加个7404反相器就成了互补波形了
ID:548551 发表于 2021-11-26 09:20
我现在用得单片机刚好是PIC架构得。我看了半天不知道理解对不对。你想GP1输出的正占空比,GP0输出的正占空比是GP0的负占空比时间,假如1现在的正占空比是10%,那么GP0输出的正占空比就应该是90%对吧。您是这意思么?
ID:27513 发表于 2021-11-26 08:19
188610329 发表于 2021-11-25 19:29
手册看了一下,发现一个被忽略的问题。
这个片子,只有35条指令,其中对位的操作指令,只有4条,而这个片 ...

按照你的方法试了一下,没有波形输出只有直流电压。
其实这个真正的原因,我个人认为不是操作快慢的问题,而是CPU离开中断子程序输出引脚信号立即再次翻转的问题。像前面我示出的一个例子,在子程序里延时即可得到想要的波形。
这个程序原意是:1。CPU给引脚付值然后延时,CPU跳出再干别的事。等延时到CPU在回去给相关引脚重新付值,就这样周而复始下去的。现在的问题就是在正程时间的延时都给了逆程时间了。
如将子程序中指令位置上下调换,只影响逆程时长,不影响正程脉宽
TMR0=224;
T0IF=0;
GP1=!GP1;
GP0=!GP1;
这样的正脉冲是4.8US,负脉宽是50.2US,频率为19.9KHz;
GP1=!GP1;
GP0=!GP1;
TMR0=224;
T0IF=0;
这样调换一下顺序,正程脉宽仍然是4.8us,但负脉宽变成了54.4us,频率降到16.8KHz;
TMR0=224;
T0IF=0;
GP1=!GP1;
TA=!GP1;
GP0=TA;
在这段里加入一个变量TA,正脉宽会变成5.48us,负脉宽缩小,频率不变仍是19.Khz;
你看从这里能不能想出解决方案来!
ID:624769 发表于 2021-11-25 19:29
手册看了一下,发现一个被忽略的问题。
这个片子,只有35条指令,其中对位的操作指令,只有4条,而这个片子速度还比较慢,周期比较长。带来的直接结果就是:
                      GP1=~GP1;//中断后设引脚反相
                        GP0=~GP1;//使GP0与GP1反相            
这看似简单的两个操作,实际上需要消耗非常多的时间来处理。
通过仔细分析这个片子拥有的35条指令,我认为:
初使状态  GP0 = 0, GP1 = 1 之后。在翻转的时候,使用:

GPIO ^= 0x03;  这一条指令来取代  你的:

                        GP1=~GP1;//中断后设引脚反相
                        GP0=~GP1;//使GP0与GP1反相      

这两条指令,是比较高效的方法。建议你尝试一下。

ID:27513 发表于 2021-11-25 18:57
dzbj 发表于 2021-11-25 12:29
老哥好 PIC一点都不懂 帮不上 我也60后 和您打个招呼

兄弟好!
ID:27513 发表于 2021-11-25 17:49
188610329 发表于 2021-11-25 17:28
PIC12F683 的PDF手册有么? 发一个上来,我研究一下看看。毕竟有些东西受限于硬件,光看代码可能忽略掉一 ...

12f683cn.pdf

3.14 MB, 下载次数: 7

ID:624769 发表于 2021-11-25 17:28
xxll 发表于 2021-11-25 13:13
谢谢提供方法!刚刚测试了一下,编译通不过,将配置语句删除,使用默认的时钟通过编译,用示波器看了一下 ...

PIC12F683 的PDF手册有么? 发一个上来,我研究一下看看。毕竟有些东西受限于硬件,光看代码可能忽略掉一些关键信息。
ID:27513 发表于 2021-11-25 13:13
lids 发表于 2021-11-25 09:29
仿真试了下,一路方波正常,两路波形就乱了
#include

谢谢提供方法!刚刚测试了一下,编译通不过,将配置语句删除,使用默认的时钟通过编译,用示波器看了一下,单脚输出频率只有10KHZ且不稳定,占空比似乎是50%但不稳定左右飘忽,怎么调示波都不能很好的同步……
ID:47286 发表于 2021-11-25 12:29
老哥好 PIC一点都不懂 帮不上 我也60后 和您打个招呼
ID:140489 发表于 2021-11-25 09:29
仿真试了下,一路方波正常,两路波形就乱了
#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GP0=0;
                                GP1=0;
        }
void timer0_init(void) //定时器0初始化使用系统默认时钟4M fosc/4 所以计数周期为1us
        {
                T0CS=0;    //timer0工作于定时器方式
                PSA=1;     //timer0不分频
                T0IF=0;    //清timer0中断标志
                TMR0=224; /*置初值 20KHz的半个周期为25us*/
                T0IE=1;    //timer0中断允许
                GIE=1;     //开全局中断
        }


void main(void)          //主程序
        {

                IO_init();         //引脚初始化函数
                timer0_init();     //定时器0初始化函数

                while(1)    //死循环
                {
                               if(flag)
                                        {
                                                GP0=1;
        //                                        GP1=!GP0;
                                        }
                                        else
                                        {
                                                GP0=0;
        //                                        GP1=!GP0;                               
                                        }

/*
                        if(flag1)
                                        {
                                                GP1=0;
                               
                                        }
                                        else
                                        {
                                                GP1=1;
                                                                               
                                        }  */                     
                }

        }

void interrupt isr(void)   //中断子程序
        {

                T0IF=0;    //清中断标志
                                TMR0=224; //定时器0置初值25us
                 
                                flag = !flag;

        }  

51hei截图20211125092516.jpg (93.61 KB, 下载次数: 106)

51hei截图20211125092516.jpg
ID:123289 发表于 2021-11-25 07:59
增加一个8位的中间 N。初始化时:N=01。 ;目的:对应 GP1=0,GP0=1。
每次中断后:
GPIO=N
N= N XOR 3   ;目的:对应的 GP1、GP0 求反,准备下次使用。
试试看。
要点:让GP1、GP0 同时改变。
ID:27513 发表于 2021-11-25 07:25
天ノ忆 发表于 2021-11-24 15:25
90后,来一个最简单的方法,因为手中没有示波器,只好麻烦楼主验证一下了,如果还是不行就自动忽略后面的吧 ...

你这种思路很好,但是无法实现!先不说你的初值不对,就中断定时1US哪个单片机都难实现。本单片机时钟4M从响应中断开始压栈执行子程序到出栈要9到15us。这还要求子程序特别简单高效才可。

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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