本帖最后由 sckocn 于 2022-6-21 15:43 编辑
在网上找到一个函数信号发生器代码。
想用arduino自带的串口绘图器显示调制的波形不知如何修改。
望请高手赐教。
***这段只修改成实时量程,希望修改成实时输出波形。
- Serial.println(frq); //波形量程输出至串口绘图器
复制代码
以下是完整代码
- /***************可调频率信号发生器*******************
- * 适用于cpu运行在16MHz的Arduino Uno或Nano
- *
- * 需要元件:
- * Arduino Uno或Nano开发板一块
- * 带开关五脚旋转编码器:
- * GND D10
- * | |
- * |___________|
- * | | |
- * D9 GND D8
- * 调节方法:顺时针增加频率,逆时针减小频率,按压开关改变调节步长
- * LCD 1602引脚:RS:D2;RW:GND;EN:D3;数据口4~7:D4~D7;用以显示当前的输出频率和调节步长
- * 100K或以上的电位器,用于调节LCD 1602的对比度
- * 无源蜂鸣器(可选)一脚接D11,一脚接地;调节频率超范围时会发声
- *
- * 输出引脚:A0~A7,在一个周期内,前半周期A0、A2、A4、A6高电平,A1、A3、A5、A7低电平;后半个周期则正好相反
- * 可以单个引脚配合地线使用,也可以相邻两个引脚一起使用
- * 注:国产Nano的A6和A7脚没有输出。
- * 输出频率:1Hz~80KHz;初始输出1KHz信号,调节步长10Hz
- *
- * 为了输出频率范围有较大跨度,程序定义了高频和低频两种模式,因而显得较为复杂
- * 高频模式下,按cpu的频率16M计数,一个时钟同期为1/16,000,000秒
- * 低频模式下,按cpu频率/256来计数,一个时钟周期为256/16,000,000秒
- * ICR1为16位寄存器,可存储0~65535之间的数,计数器在每个时钟周期增加1,当数值与ICR1中数值相等时重置为零,
- * 同时触发程序中的ISR()中断,所以改变ICR1的值可以改变输出频率
- *
- * “无线电实验室” 2020年6月1日
- *****************************************************/
- #include<LiquidCrystal.h>
- const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; //LCD1602引脚定义
- LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
- const int SW = 10, CW = 9, ACW = 8; //旋转编码器引脚:按键、顺时针、逆时针
- int PIN[2] ={CW,ACW};
- bool oldState[2];
- bool mode = 1; //高频械式1,低频模式0; 500Hz~80KHz对应高频模式,1~500Hz为低频模式
- float STEP = 10; //初始频率调节步长,可选值为:0.1、1、10、100、1000
- float frq = 1000; //初始输出信号频率,可选范围 1Hz~80KHz
- float temp;
- byte TP = 0b01010101;
- void setup() {
- Serial.begin(9600); //定义Arduino 串口输出
- initInterrupt(); //初始化中断设置
- DDRC = 0xFF; //将A0~A7均设为输出模式
- pinMode(SW,INPUT_PULLUP);
- pinMode(PIN[0],INPUT_PULLUP);
- pinMode(PIN[1],INPUT_PULLUP);
- oldState[0]=digitalRead(PIN[0]);
- oldState[1]=digitalRead(PIN[1]);
- lcd.begin(16,2);
- lcd.print("Freq:");
- lcd.print(frq);
- lcd.setCursor(0,1);
- lcd.print("Step:");
- lcd.print(STEP);
-
- }
- void loop() {
- Serial.println(frq); //波形量程输出至串口绘图器
- if(isChanged(0))//判断为顺时针旋转时
- {
- frq +=STEP;
- if(frq>=500 && mode==0)//需要更改分频模式的情况
- {
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10; //高频模式,分频器1
- mode = 1;
- }
- if(frq>80000){
- frq = 80000;
- tone(11,600,50); //最高80KHz,超出量程播放提示音
- }
- temp = 31250/frq*(1+255*mode);
- ICR1 = int(temp);
- TCNT1=0;
- lcd.setCursor(5,0);
- lcd.print(frq);
- lcd.print(" ");
- delay(1);
- }
- if(isChanged(1))//判断为逆时针旋转编码器
- {
- frq -= STEP;
- if(frq<500 && mode==1)//需要改为低频模式的情况
- {
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 1<<CS12 | 0<<CS11 | 0<<CS10; //低频模式,分频器256
- mode = 0;
- }
- if(frq<1){
- frq = 1;
- tone(11,600,50);//频率最低1Hz,超出时发出滴的声音
- }
- temp = 31250/frq*(1+255*mode);
- ICR1 = int(temp);
- TCNT1=0;
- lcd.setCursor(5,0);
- lcd.print(frq);
- lcd.print(" ");
- delay(1);
- }
- //判断按键是否按下
- if(!digitalRead(SW)){
- delay(140);
- if(!digitalRead(SW)){
- STEP*=10;
- if(STEP>1000)
- STEP=0.1;
- }
- lcd.setCursor(5,1);
- lcd.print(STEP);
- lcd.print(" ");
- }
- }
- //判断iPin脚电平是否变化,是返回1,否则返回0
- bool isChanged(int iPin){
- bool newState = digitalRead(PIN[iPin]);
- if(newState!=oldState[iPin]){
- oldState[0]=newState;
- oldState[1]=newState;
- return 1;
- }
- else
- return 0;
- }
- void initInterrupt(){
- TCCR1A = 0; //普通模式
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10; //CTC模式:ICR1触发,初始分频:cpu主频16MHz
- ICR1 = int(8000000/frq); //寄存器,计数器达到该值时产生中断信号
- TIMSK1 |= 1<<ICIE1; //允许捕捉事件中断
- }
- //中断函数
- ISR(TIMER1_CAPT_vect){
- TP = ~TP;
- PORTC = TP;
- }
复制代码
电路:
参考:(比如这个代码LOOP)
- float x=0;
- float y=0;
- const float pi=3.14;
- int z=0;
- float v=0;
- int w=0;
- boolean OK=true;
- void setup() {
- Serial.begin(9600);
- }
- // the loop function runs over and over again forever
- void loop() {
- if (w==0){
- v=x*pi/180; // making deg in radians
- y=sin(v); //calculate sinus
- z=y*250; // calculate duty cycle(250 not 255 because will help to turn off transistors)
- delay(100);
- if(OK==true){
- x=x+0.689;// increase the angle
- }
- }
- if (x>90){
- OK=false;
- }
- if (OK==false){
- x=x-0.689; //decreasing the angle for the other half
- }
- Serial.println(z);// on the serial monitor will appear duty cycles between 0 and 180 deg
- }
复制代码
代码添加后(二合一)
- /***************可调频率信号发生器*******************
- * 适用于cpu运行在16MHz的Arduino Uno或Nano
- *
- * 需要元件:
- * Arduino Uno或Nano开发板一块
- * 带开关五脚旋转编码器:
- * GND D10
- * | |
- * |___________|
- * | | |
- * D9 GND D8
- * 调节方法:顺时针增加频率,逆时针减小频率,按压开关改变调节步长
- * LCD 1602引脚:RS:D2;RW:GND;EN:D3;数据口4~7:D4~D7;用以显示当前的输出频率和调节步长
- * 100K或以上的电位器,用于调节LCD 1602的对比度
- * 无源蜂鸣器(可选)一脚接D11,一脚接地;调节频率超范围时会发声
- *
- * 输出引脚:A0~A7,在一个周期内,前半周期A0、A2、A4、A6高电平,A1、A3、A5、A7低电平;后半个周期则正好相反
- * 可以单个引脚配合地线使用,也可以相邻两个引脚一起使用
- * 注:国产Nano的A6和A7脚没有输出。
- * 输出频率:1Hz~80KHz;初始输出1KHz信号,调节步长10Hz
- *
- * 为了输出频率范围有较大跨度,程序定义了高频和低频两种模式,因而显得较为复杂
- * 高频模式下,按cpu的频率16M计数,一个时钟同期为1/16,000,000秒
- * 低频模式下,按cpu频率/256来计数,一个时钟周期为256/16,000,000秒
- * ICR1为16位寄存器,可存储0~65535之间的数,计数器在每个时钟周期增加1,当数值与ICR1中数值相等时重置为零,
- * 同时触发程序中的ISR()中断,所以改变ICR1的值可以改变输出频率
- *
- * “无线电实验室” 2020年6月1日
- *****************************************************/
- <b>//绘图器相关定义-Add</b>
- <font color="#9932cc">float x=0;
- float y=0;
- const float pi=3.14;
- int z=0;
- float v=0;
- int w=0;
- boolean OK=true;</font>
- //原代码
- #include<LiquidCrystal.h>
- const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; //LCD1602引脚定义
- LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
- const int SW = 10, CW = 9, ACW = 8; //旋转编码器引脚:按键、顺时针、逆时针
- int PIN[2] ={CW,ACW};
- bool oldState[2];
- bool mode = 1; //高频械式1,低频模式0; 500Hz~80KHz对应高频模式,1~500Hz为低频模式
- float STEP = 10; //初始频率调节步长,可选值为:0.1、1、10、100、1000
- float frq = 1000; //初始输出信号频率,可选范围 1Hz~80KHz
- float temp;
- byte TP = 0b01010101;
- void setup() {
- Serial.begin(9600); //定义Arduino 串口输出波特率
- initInterrupt(); //初始化中断设置
- DDRC = 0xFF; //将A0~A7均设为输出模式
- pinMode(SW,INPUT_PULLUP);
- pinMode(PIN[0],INPUT_PULLUP);
- pinMode(PIN[1],INPUT_PULLUP);
- oldState[0]=digitalRead(PIN[0]);
- oldState[1]=digitalRead(PIN[1]);
- lcd.begin(16,2);
- lcd.print("Freq:");
- lcd.print(frq);
- lcd.setCursor(0,1);
- lcd.print("Step:");
- lcd.print(STEP);
-
- }
- void loop() {
- <b>//绘图器相关-Add</b>
- <font color="#9932cc">{
- if (w==0){
- v=x*pi/180; // making deg in radians
- y=sin(v); //calculate sinus
- z=y*250; // calculate duty cycle(250 not 255 because will help to turn off transistors)
- delay(100);
- if(OK==true){
- x=x+0.689;// increase the angle
- }
- }
- if (x>90){
- OK=false;
- }
- if (OK==false){
- x=x-0.689; //decreasing the angle for the other half
- }
- Serial.println(z,frq); //波形量程输出至串口绘图器
- }</font>
- //原代码
- if(isChanged(0))//判断为顺时针旋转时
- {
- frq +=STEP;
- if(frq>=500 && mode==0)//需要更改分频模式的情况
- {
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10; //高频模式,分频器1
- mode = 1;
- }
- if(frq>80000){
- frq = 80000;
- tone(11,600,50); //最高80KHz,超出量程播放提示音
- }
- temp = 31250/frq*(1+255*mode);
- ICR1 = int(temp);
- TCNT1=0;
- lcd.setCursor(5,0);
- lcd.print(frq);
- lcd.print(" ");
- delay(1);
- }
- if(isChanged(1))//判断为逆时针旋转编码器
- {
- frq -= STEP;
- if(frq<500 && mode==1)//需要改为低频模式的情况
- {
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 1<<CS12 | 0<<CS11 | 0<<CS10; //低频模式,分频器256
- mode = 0;
- }
- if(frq<1){
- frq = 1;
- tone(11,600,50);//频率最低1Hz,超出时发出滴的声音
- }
- temp = 31250/frq*(1+255*mode);
- ICR1 = int(temp);
- TCNT1=0;
- lcd.setCursor(5,0);
- lcd.print(frq);
- lcd.print(" ");
- delay(1);
- }
- //判断按键是否按下
- if(!digitalRead(SW)){
- delay(140);
- if(!digitalRead(SW)){
- STEP*=10;
- if(STEP>1000)
- STEP=0.1;
- }
- lcd.setCursor(5,1);
- lcd.print(STEP);
- lcd.print(" ");
- }
- }
- //判断iPin脚电平是否变化,是返回1,否则返回0
- bool isChanged(int iPin){
- bool newState = digitalRead(PIN[iPin]);
- if(newState!=oldState[iPin]){
- oldState[0]=newState;
- oldState[1]=newState;
- return 1;
- }
- else
- return 0;
- }
- void initInterrupt(){
- TCCR1A = 0; //普通模式
- TCCR1B = 1<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10; //CTC模式:ICR1触发,初始分频:cpu主频16MHz
- ICR1 = int(8000000/frq); //寄存器,计数器达到该值时产生中断信号
- TIMSK1 |= 1<<ICIE1; //允许捕捉事件中断
- }
- //中断函数
- ISR(TIMER1_CAPT_vect){
- TP = ~TP;
- PORTC = TP;
- }
复制代码
代码合二为一后串口监视器和绘图器截图。怎样才能让它正常、真正合二为一呢?
|