xxll 发表于 2021-12-2 17:58 门外汉不是理由 与或非编程基础类知道,不管是你半路出家还是科班出身,不管你专业人士还业余爱好,也不管你是长期爱好还是一时性起 这基础知道是肯定要学的,如果不想学,那就不要搞单片机了 不是打击你,而是没有基础的话,那这单片机玩起来实在太累了,还浪费时间 从你这个问题就可以看出来了,如果当初,你多花一个小时的时间去看一下端口设置,那你就不会在这50%占空比上面花那么多的时间和精力 个人感觉,很多时候,一个自己几天甚至半个月都搞不定的东西,很有可能只是一个简单的东西而已,只是自己没有严谨认真的去看相关的资料而已 我之前就经常碰到这样的问题,一个小小的东西,搞几天都搞不好,怎么找都找不到问题,最后干脆之前的代码都不要,从头再看资料,一步一步的来,一下子就发现问题了,而且,不过是一个很基础很简的问题而已,只是自己老是钻牛角尖而已 所以,基础很重要,不管你多大年纪,不管你是出什么目的学单片机,多看一下基础,不会有坏处 |
xxll 发表于 2021-12-2 17:44 GPIO |= 0x06;//这个1,2位输出高电平,不改变其他位 GPIO &= 0XF9;//这个1,2位输出低电平,同样不改变其他位 |
xxll 发表于 2021-12-2 17:44 抱歉,是我的锅,没复验就发了。 应该是 gpio ^= 0x06; 与或计算,即1变0,0变1。手机发帖排版大小写就不修改了。 |
Y_G_G 发表于 2021-12-2 17:49 我不说过我是个门外汉吗!与我也不会呀 |
Y_G_G 发表于 2021-12-2 17:49 打错了gpio^=0x06 |
xxll 发表于 2021-12-2 17:44 GPIO |= 0x06; 这个是不行的,或指令不能输出低电平的 你自己也要思考一下的嘛 肯定是要用&的嘛 |
188610329 发表于 2021-12-2 13:40 你好,这个或运算是如何实现的,我不懂啦。如0x06=0b00000110,若原GPIO=0b00000010或运算后它不还是0b00000110吗? |
老哥,如果你要实现 产品副本.jpg 那样的波形的话,你改写端口的指令必须修改。 void interrupt isr(void) //中断子程序 { TMR0=224; T0IF=0; GPIO |= 0x06; // 要用字节改写 GPIO总线, 而不是用位改写 IO } |
xxll 发表于 2021-12-2 11:43 GPIO就是一个端口的好不好,直接赋值GPIO端口应该就可以得到你要波形了{ GPIO=0x01;//GP0 GP1输出,自己也可以改其它的IO,如果不想影响其它IO,可以用& ON=0; } else { GPIO=0x02; ON=1; } |
本帖最后由 xxll 于 2021-12-2 12:03 编辑 Y_G_G 发表于 2021-12-2 11:26 不是同一端口,原来是GP0与GP1,现在改为GP1与GP2了,其实道理是一样的厅 是我理解错了是同一个端口寄存器,因为只有8个引脚的单片机。 |
xxll 发表于 2021-12-2 11:05 这GP1和GP0是在同一个端口的吗?没有看数据手册,不知道 不同端口的话,那是要两条指令,那是肯定要有延时的 如果是同一个端口,那就是一条指令就行了if(ON) { PORTD=0x01;//假设是RD端口输出 ON=0; } else { PORTD=0x02; ON=1; } |
taotie 发表于 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; } |
虽然占空比没达到百分之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; } |
xxll 发表于 2021-11-27 09:08 从你发的手册上看, ANSEL 控制引脚是模拟输入,还是数字输出。 如果 有 位置1则为模拟输入,如果该位置0则为数字输出。 手册上看,上电后 ANSEL 的初值不为0。 并且,手册上还说,上电后端口初始化 ANSEL 需要 置 0 复位。 另外,和GPIO有关的寄存器,总共有11个, ![]() 此表中,没有打阴影的部分,都是会影响GPIO的输出的设置。 通过此表也能看到,ANSEL 不设置0的话,GPIO0~GPIO3 默认为模拟输入。 |
Y_G_G 发表于 2021-11-26 14:36 关于这里的TMRO=224是因为时钟是8M时设的值,(256-224)*0.5=16us在8M时钟时CPU执行中断大约耗费9us (后面也证实了),16+9=25 |
xxll 发表于 2021-11-27 09:08 还要添加一条: CMCON0=0x07; |
xxll 发表于 2021-11-27 09:08 你试过增加ANSEL=0x00;这语句没有? ANSEL 是要先清除的! |
188610329 发表于 2021-11-26 21:34 ANSEL寄存器是为模拟信号输入设置寄存器和它没关系,端口就这两个寄存器TRISIO和GPIO |
老哥, 你说…… ,会不会是因为: ANSEL = 0; 这句没写的关系啊? 我琢磨了很久,你在顶楼说的,删除了GP1 = !GP0; 就没输出了, 你觉得不应该,我也觉得不应该,所以,我在想,是不是一开始咱们就没找对方向? 其实就是端口的初始化没有做好? 所以没有输出? |
18434225 发表于 2021-11-26 18:45 正半周25us+负半周25us,总周期是50us哪来的40KHZ,这个单片机20KHZ都可能做不督到,还40K 双脚输出互补的方波如果拿来驱动逆变半桥,GP1=GP0想想是什么后果?再都为了试验,前面说过都试过了,没有变化,是一样的。这东西折腾很久了,不是我执着,论个所以然,早就放弃了…… |
xxll 发表于 2021-11-26 18:19 你把完整的代码上传一下 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置初值,先看结果,这设置放后面 } |
Y_G_G 发表于 2021-11-26 14:36 这位老师好!我把你的方案和数据测试结果汇报给你:时钟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正脉冲太窄,你看如何解决? |
还在折腾这个? 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; } } |
xqleft 发表于 2021-11-26 09:20 我要的就是一个引脚上正50%,负50%就这样简单,要求是用定时器0实现,频率20KHZ |
lids 发表于 2021-11-25 09:29 一路方波正常很好~~加个7404反相器就成了互补波形了 |
我现在用得单片机刚好是PIC架构得。我看了半天不知道理解对不对。你想GP1输出的正占空比,GP0输出的正占空比是GP0的负占空比时间,假如1现在的正占空比是10%,那么GP0输出的正占空比就应该是90%对吧。您是这意思么? |
188610329 发表于 2021-11-25 19:29 按照你的方法试了一下,没有波形输出只有直流电压。 其实这个真正的原因,我个人认为不是操作快慢的问题,而是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; 你看从这里能不能想出解决方案来! |
手册看了一下,发现一个被忽略的问题。 这个片子,只有35条指令,其中对位的操作指令,只有4条,而这个片子速度还比较慢,周期比较长。带来的直接结果就是: GP1=~GP1;//中断后设引脚反相 GP0=~GP1;//使GP0与GP1反相 这看似简单的两个操作,实际上需要消耗非常多的时间来处理。 通过仔细分析这个片子拥有的35条指令,我认为: 初使状态 GP0 = 0, GP1 = 1 之后。在翻转的时候,使用: GPIO ^= 0x03; 这一条指令来取代 你的: GP1=~GP1;//中断后设引脚反相 GP0=~GP1;//使GP0与GP1反相 这两条指令,是比较高效的方法。建议你尝试一下。 |
dzbj 发表于 2021-11-25 12:29 兄弟好! |
188610329 发表于 2021-11-25 17:28 |
3.14 MB, 下载次数: 7
xxll 发表于 2021-11-25 13:13 PIC12F683 的PDF手册有么? 发一个上来,我研究一下看看。毕竟有些东西受限于硬件,光看代码可能忽略掉一些关键信息。 |
lids 发表于 2021-11-25 09:29 谢谢提供方法!刚刚测试了一下,编译通不过,将配置语句删除,使用默认的时钟通过编译,用示波器看了一下,单脚输出频率只有10KHZ且不稳定,占空比似乎是50%但不稳定左右飘忽,怎么调示波都不能很好的同步…… |
老哥好 PIC一点都不懂 帮不上 我也60后 和您打个招呼 |
仿真试了下,一路方波正常,两路波形就乱了 #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)
增加一个8位的中间 N。初始化时:N=01。 ;目的:对应 GP1=0,GP0=1。 每次中断后: GPIO=N N= N XOR 3 ;目的:对应的 GP1、GP0 求反,准备下次使用。 试试看。 要点:让GP1、GP0 同时改变。 |
天ノ忆 发表于 2021-11-24 15:25 你这种思路很好,但是无法实现!先不说你的初值不对,就中断定时1US哪个单片机都难实现。本单片机时钟4M从响应中断开始压栈执行子程序到出栈要9到15us。这还要求子程序特别简单高效才可。 |