在网上找到一个函数信号发生器代码。
想用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;
}
参考代码:
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;
}
输出的频率用示波器测试正常,只是Arduino串口监视器和绘图器的不正常。
请赐教
