找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5064|回复: 53
收起左侧

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

  [复制链接]
ID:27513 发表于 2021-11-24 11:18 | 显示全部楼层 |阅读模式
自我介绍下:60后从业模电,自封工程师,动手能力强。学单片机历程30年,学级仍是未入门的学前班。所以各位看官都是我的老师,各位的每句话都能使我进步!期望大家都出一份正能量!废话不说入正题:
PIC12F683单片机,编程平台MPLAB IDE -V8.84  编译器HI-TECH-PICC_9.83
无单片机开发板,有RF809H编程器,有GA1202CAL示波器
实验要求单片机GP0和GP1输出20KHz占空比为50%的互补方波

C程序:
#include <pic.h>

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

        void interrupt isr(void)   //中断子程序
                {
                        TMR0=0xE0; //定时器0置初值25us
                        T0IF=0;    //清中断标志
                        GP0=~GP0;  //GP0位取反
                        GP1=!GP0;  //使GP1引脚取反GP0
                        /*在这里废寝忘食3总天,一度引起孙子的奶奶发飙
                                也没有折腾出正确的结果*/                                 
                }  
void main(void)          //主程序
        {
        
                IO_init();         //引脚初始化函数
                timer0_init();     //定时器0初始化函数
        
                while(1)    //死循环
                {
               
                        
                }
                        
        }

写入单片机;手工搭建最小系统上示波器看波形结果频率是26.3KHz,GP0引脚正占空比只有12.6%,负占空比87.3%;GP1引脚正占空比86.3%,负占空比13.6%幅值5.04V
删除中断子程序里的GP1=!GP0语句结果GP0引脚示波器上只有一条5.17V的直线没有波形了,频率显示为小于10Hz.
大家说怪不怪!!本应该GP0输出信号不受影响的怎么就没有了呢????
接下来就是折腾了反复换TMR0的初值,最后试到0xE0时频率是19.96KHz正占空比9.6%负占空比是90.4%,也就是说正脉冲的宽度是4.8us这个值基本是恒定的试了下,从10KHz到30KHz这个值不变.然后大发现这个4.8us竟然是执行GP1=!GP0 这条语句所耗费的时间,所以上述删除这条语句示波器上只显示一直线。


GAS0002副本.jpg
回复

使用道具 举报

ID:27513 发表于 2021-11-24 11:31 | 显示全部楼层
本帖最后由 xxll 于 2021-11-24 12:03 编辑

现在的问题就是怎样才能使正负波形占空比为50%  ?

于是我又timer2这个定时器来做程序如下:
#include <pic.h>
#define uchar unsigned char
#define uint  unsigned int
        uchar TA,TB;
void IO_init(void) /*端口初始化*/
        {

                TRISIO=0x00;
               
        }
void timer2_init(void) //fosc/4   8M所以计数周期为0.5us
        {
                T2CON=0b00000101;        //timer2控制寄存器设置        
                PR2=24;        //25us比较数字
                PEIE=1;        //模块中断使能
                TMR2IE=1;                //定时器2中断使能
                GIE=1;       //        开全局中断
        }

        void interrupt isr(void)
                {
                        GP1=~GP1;//中断后设引脚反相
                        GP0=~GP1;//使GP0与GP1反相                        
                        TMR2IF=0;/*TMR2溢出标志清零*/               
                }  
void main(void)
        {
                __CONFIG(FOSC_INTOSCIO&WDTE_OFF);//系统配置,使用内置时钟,关看门狗
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3条设置时钟为8M
                IO_init();//端口初始化
                timer2_init();//timer2初始化
                GPIO=0X00;//全部端口设为0
                while(1)  //死循环
                {
               
                        
                }
                        
        }
GAS0003副本.jpg
回复

使用道具 举报

ID:624769 发表于 2021-11-24 13:42 | 显示全部楼层
PIC 没玩过,本不该发言,但是看你帖子实在冷清,深感年纪大了学单片机之不易……,
作为70后,在你身上看到10年后的自己,所以多多少少想帮你顶一把。
虽然PIC没有玩过, 有些道理应该是互通的所以说两句。

                       GP0=~GP0;  //GP0位取反
                        GP1=!GP0;  //使GP1引脚取反GP0
基于单片机的工作原理,这里很可能得不到你希望的结果…… 举个简单的例子。
GP0 = ~GP0; 这里的等号左边 和 等号右边,其实是不同的东西。
等号的右边,是当前GP0的电平状态,综合了外部电平和内部设置之后的最后结果,然后通过~取反
等号左边,是你给GP0 设置的新状态即会改变GP0的内部电平关系,然后通过这个内部关系再去改变端口的外部关系。
当你运行完  GP0 = ~GP0   立刻运行  GP1=!GP0; 此时读取的 GP0, 如上所说是结合内部设置和外部电平综合后的一个状态,而不是你刚刚赋值的结果,由于各种单片机不同我不能说100%,但是有很大的概率,这个时候的GP0,是并没有完成  GP0 = ~GP0 这个操作后更新 的状态。 但,也有可能已经完成了更新。这个不好判断,所以在时序允许的情况下,一般应该这么写代码。
                   GP1= GP0;  //使GP1引脚取GP0
                   GP0= !GP0;  //GP0位取反
这样能保障,两次读到的GP0 是相等的。
如果,你一定要先改GP0, 再改GP1 那么也可以用一个中间变量
                   F0 = GP0;
                   GP0 = !F0;
                   GP1 = F0;
这样是比较安全的操作。
回复

使用道具 举报

ID:313048 发表于 2021-11-24 13:55 | 显示全部楼层
本帖最后由 AUG 于 2021-11-24 14:01 编辑
xxll 发表于 2021-11-24 11:31
现在的问题就是怎样才能使正负波形占空比为50%  ?

于是我又timer2这个定时器来做程序如下:

从你这个图可以看出,那个脉冲是你每次进去之后GP0=~GP0取反的结果,后面变低是因为你又GP1=!GP0,使其变低了.建议如下操作
void main()
{
timer_init();//25us一次中断   40KHz
GP0 = 1;  //起始值相反
GP1 = 0;
while(1);
}
interrupt timer(void)
{
//重装计数值
//清中断
GP1=GP0;
GP0=~GP0;
}
回复

使用道具 举报

ID:892596 发表于 2021-11-24 14:18 | 显示全部楼层
用过一个仿PIC的芯片。
用的T0做的510US定时:
1.jpg
用的T1做的38KHz的方波:
2.jpg
中断里的IO翻转。
3.jpg
回复

使用道具 举报

ID:892596 发表于 2021-11-24 14:19 | 显示全部楼层
不确定寄存器完全一致的,你可以参考一下,看着修改。
回复

使用道具 举报

ID:401564 发表于 2021-11-24 14:26 | 显示全部楼层
中断程序这样改试一下:
void interrupt isr(void)   //中断子程序
                {
                        TMR0=0xE0; //定时器0置初值25us
                        T0IF=0;    //清中断标志
                        GP1=GP0;  //使GP1引脚取反GP0后的GP0   
                        GP0=~GP0;  //GP0位取反                                                
                }
其它参考意见:
PIC我用过,个人感觉PIC实在不适合单片机入门,更多的是工业产品才用的,很多操作是有严格要求的,比如硬件堆栈,甚至很多学单片机的对堆栈也只是百度大概的看一遍,但真正到PIC硬件堆栈的时候,问题就出来了
IO的数据方向要注意,中断只有一个入口.......
数据手册是肯定要一边写代码一边看的,但PIC的8位单片机数据手册都是汇编的,印象中是没有C的,所以,汇编指令最好是也要会一点,不要求能写程序,至少对着指令能看明白

回复

使用道具 举报

ID:298123 发表于 2021-11-24 15:11 | 显示全部楼层
一般来说,端口设置和读取的寄存器是分开的,设置后马上读取,单片机速度太快,读取状态值不一定是稳定后的值。最好定义个变量 bit status,   中断里改变status = !status; 然后赋值给端口寄存器
回复

使用道具 举报

ID:123289 发表于 2021-11-24 15:12 | 显示全部楼层
增加一个中间变T.
每次中断后:
GP0=T
T=!T
GP1=T
试试看。
回复

使用道具 举报

ID:123289 发表于 2021-11-24 15:13 | 显示全部楼层
如果成功,再告诉你原因。不成功就罢了。
回复

使用道具 举报

ID:139866 发表于 2021-11-24 15:25 | 显示全部楼层
90后,来一个最简单的方法,因为手中没有示波器,只好麻烦楼主验证一下了,如果还是不行就自动忽略后面的吧,一般来说对定时器要求较高,定时器中断里处理的代码越少越好,能少就尽量少,以下是代码
  1. #include <pic.h>

  2. char i = 0;

  3. void IO_init(void) /*端口初始化*/
  4. {
  5.         TRISIO=0x00;
  6.         GPIO=0X00;
  7. }
  8. void timer0_init(void) //定时器0初始化使用系统默认时钟4M fosc/4 所以计数周期为1us
  9. {
  10.         T0CS=0;    //timer0工作于定时器方式
  11.         PSA=1;     //timer0不分频
  12.         T0IF=0;    //清timer0中断标志
  13.         TMR0=0x01; /*置初值 20KHz的半个周期为25us*/
  14.         T0IE=1;    //timer0中断允许
  15.         GIE=1;     //开全局中断
  16. }

  17. void main()
  18. {
  19.     IO_init();         //引脚初始化函数
  20.     timer0_init();     //定时器0初始化函数
  21.         while()
  22.         {
  23.                 if(i >= 50) {
  24.                         i = 1;
  25.                 }else if(i >= 25) {
  26.                         GP0 = 1;  
  27.                         GP1 = 0;
  28.                 }else if(i >= 0) {
  29.                         GP0 = 0;
  30.                         GP1 = 1;
  31.                 }
  32.         }
  33. }

  34. void interrupt isr(void)   //中断子程序
  35. {
  36.     TMR0 = 0x01; //定时器0置初值1us
  37.     T0IF = 0;    //清中断标志                       
  38.         i ++;
  39. }
复制代码

回复

使用道具 举报

ID:27513 发表于 2021-11-24 16:38 | 显示全部楼层
yzwzfyz 发表于 2021-11-24 15:12
增加一个中间变T.
每次中断后:
GP0=T

首先谢谢你,你这种方法我之前也试过,正脉冲的宽度只增加2.5us
回复

使用道具 举报

ID:27513 发表于 2021-11-24 17:26 | 显示全部楼层
188610329 发表于 2021-11-24 13:42
PIC 没玩过,本不该发言,但是看你帖子实在冷清,深感年纪大了学单片机之不易……,
作为70后,在你身上看 ...

感谢您的参与,你说的第一种GP0=~GP0;GP1=!GP0;刚试过结果脉宽没有改变.这种顺序改变在示波器上观看没有变化的.当然,我知道编程是要讲究时序的,否则实际应用中会出大问题的!至于第二种方法我在早些时候也试过,中间加一个变量操作,确实增加了2.5us宽度.再次谢谢!
回复

使用道具 举报

ID:27513 发表于 2021-11-24 17:53 | 显示全部楼层
本帖最后由 xxll 于 2021-11-25 07:00 编辑

谢谢各位老师,在这么短的时间内就有许多人参与,出乎我的意料,心情非常激动!大家的建议我一定抽时间一一测试总结经验.再报告给各位.开先也偿试出一个接近答案的程序,但是他不符合中断的原则.CPU在正程中断子程序里总总耗费25us.现在也把这个程序给贴出来:
#include <pic.h>
#define uchar unsigned char
#define uint  unsigned int
        uchar TA,TB;
void IO_init(void) /*端口初始化*/
        {

                TRISIO=0x00;
               
        }
void timer2_init(void) //fosc/4   8M所以计数周期为0.5us
        {
                T2CON=0b00000101;        //timer2控制寄存器设置        
                PR2=24;        //25us比较数字
                PEIE=1;        //中断使能
                TMR2IE=1;                //中断使能
                GIE=1;       //        开全局中断
        }
void delay(void)//延时函数
{
         uchar i;
         for(i=2 ;i ; i--);                 
}

/*************************************************/
/*中断子程序正脉宽为24.6us负脉宽为25.626us,频率为19.92KHz*/
/*************************************************/
        void interrupt isr(void)
                {
                        GP1=~GP1;//中断后设引脚反相
                        delay(); //延时
                        TA=GP1;//此项也是为延时2.5us
                        GP0=~TA;//使GP0与GP1反相                        
                        TMR2IF=0;/*TMR2溢出标志清零*/               
                }  
void main(void)
        {
                __CONFIG(FOSC_INTOSCIO&WDTE_OFF);//系统配置,使用内置时钟,关看门狗
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3条设置时钟为8M
                IO_init();//端口初始化
                timer2_init();//timer2初始化
                GPIO=0X00;//全部端口设为0
                while(1)  //死循环
                {
               
                        
                }
                        
        }

GAS0004副本.jpg
回复

使用道具 举报

ID:27513 发表于 2021-11-25 07:25 | 显示全部楼层
天ノ忆 发表于 2021-11-24 15:25
90后,来一个最简单的方法,因为手中没有示波器,只好麻烦楼主验证一下了,如果还是不行就自动忽略后面的吧 ...

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

使用道具 举报

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: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
回复

使用道具 举报

ID:47286 发表于 2021-11-25 12:29 | 显示全部楼层
老哥好 PIC一点都不懂 帮不上 我也60后 和您打个招呼
回复

使用道具 举报

ID:27513 发表于 2021-11-25 13:13 | 显示全部楼层
lids 发表于 2021-11-25 09:29
仿真试了下,一路方波正常,两路波形就乱了
#include

谢谢提供方法!刚刚测试了一下,编译通不过,将配置语句删除,使用默认的时钟通过编译,用示波器看了一下,单脚输出频率只有10KHZ且不稳定,占空比似乎是50%但不稳定左右飘忽,怎么调示波都不能很好的同步……
回复

使用道具 举报

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

PIC12F683 的PDF手册有么? 发一个上来,我研究一下看看。毕竟有些东西受限于硬件,光看代码可能忽略掉一些关键信息。
回复

使用道具 举报

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

12f683cn.pdf

3.14 MB, 下载次数: 7

回复

使用道具 举报

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

兄弟好!
回复

使用道具 举报

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-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:548551 发表于 2021-11-26 09:20 | 显示全部楼层
我现在用得单片机刚好是PIC架构得。我看了半天不知道理解对不对。你想GP1输出的正占空比,GP0输出的正占空比是GP0的负占空比时间,假如1现在的正占空比是10%,那么GP0输出的正占空比就应该是90%对吧。您是这意思么?
回复

使用道具 举报

ID:342822 发表于 2021-11-26 09:38 | 显示全部楼层
lids 发表于 2021-11-25 09:29
仿真试了下,一路方波正常,两路波形就乱了
#include

一路方波正常很好~~加个7404反相器就成了互补波形了
回复

使用道具 举报

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

我要的就是一个引脚上正50%,负50%就这样简单,要求是用定时器0实现,频率20KHZ
回复

使用道具 举报

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 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 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 20:44 | 显示全部楼层
18434225 发表于 2021-11-26 18:45
从你这个图可以看出,那个脉冲是你每次进去之后GP0=~GP0取反的结果,后面变低是因为你又GP1=!GP0,使其变低 ...

正半周25us+负半周25us,总周期是50us哪来的40KHZ,这个单片机20KHZ都可能做不督到,还40K
双脚输出互补的方波如果拿来驱动逆变半桥,GP1=GP0想想是什么后果?再都为了试验,前面说过都试过了,没有变化,是一样的。这东西折腾很久了,不是我执着,论个所以然,早就放弃了……
回复

使用道具 举报

ID:624769 发表于 2021-11-26 21:34 | 显示全部楼层
老哥, 你说…… ,会不会是因为:

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

我琢磨了很久,你在顶楼说的,删除了GP1 = !GP0;  就没输出了, 你觉得不应该,我也觉得不应该,所以,我在想,是不是一开始咱们就没找对方向? 其实就是端口的初始化没有做好? 所以没有输出?
回复

使用道具 举报

ID:27513 发表于 2021-11-27 09:08 | 显示全部楼层
188610329 发表于 2021-11-26 21:34
老哥, 你说…… ,会不会是因为:

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

ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO
回复

使用道具 举报

ID:27513 发表于 2021-11-27 09:23 | 显示全部楼层
xxll 发表于 2021-11-26 20:44
正半周25us+负半周25us,总周期是50us哪来的40KHZ,这个单片机20KHZ都可能做不督到,还40K
双脚输出互补 ...

#include <pic.h>
#define uchar unsigned char
uchar ON;
void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO=0X00;
        }
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 interrupt isr(void)   //中断子程序
                {
                        TMR0=224; //定时器0置初值25us               
                        T0IF=0;    //清中断标志                                       
                if(ON)
                        {
        //                TMR0=224; //定时器0置初值25us               
        //                T0IF=0;    //清中断标志                       
                        GP2=0;
                        GP1=1;
                        ON=0;
                        }
                else
                        {
                //        TMR0=224; //定时器0置初值25us               
                //        T0IF=0;    //清中断标志
                        GP1=0;
                        GP2=1;
                        ON=1;                       
                        }
       
                //        GP0=~GP0;  //GP0位取反
                //        GP1=!GP0;  //使GP1引脚取反GP0               
               
                        /*在这里废寝忘食3总天,一度引起孙子的奶奶发飙
                                也没有折腾出正确的结果*/                                
                }  
void main(void)          //主程序
        {
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3条设置时钟为8M
                IO_init();         //引脚初始化函数
                timer0_init();     //定时器0初始化函数
                GP1=1;
                GP2=0;
                while(1)    //死循环
                {
               
                       
                }
                       
        }
花括号里的顺序谁在前谁就是窄脉冲,和TMR0、T0IF所在位置无关,但和频率高低有较大的关系。稍后我将发个统计表格上来供大家研究!!

GAS0002副本.jpg
GAS0004副本.jpg
回复

使用道具 举报

ID:401564 发表于 2021-11-27 12:00 | 显示全部楼层
xxll 发表于 2021-11-27 09:08
ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO

你试过增加ANSEL=0x00;这语句没有?
ANSEL 是要先清除的!
回复

使用道具 举报

ID:401564 发表于 2021-11-27 12:25 | 显示全部楼层
xxll 发表于 2021-11-27 09:08
ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO

还要添加一条:
CMCON0=0x07;
回复

使用道具 举报

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: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.png
此表中,没有打阴影的部分,都是会影响GPIO的输出的设置。
通过此表也能看到,ANSEL 不设置0的话,GPIO0~GPIO3 默认为模拟输入。
回复

使用道具 举报

ID:342822 发表于 2021-11-27 22:34 | 显示全部楼层
虽然占空比没达到百分之50,但已经是互补方波了 屏幕截图(76).png



/* 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:342822 发表于 2021-11-28 00:10 | 显示全部楼层
本帖最后由 taotie 于 2021-11-29 14:49 编辑

屏幕截图(111).png

相差无几
时钟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;                       

        }  

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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