主要为单片机开发,其占用 ROM 少,同时采用查表以减少运行时间
只保存四分之一的正弦波数据以供查表
可以通过PWM、DAC生成正弦波,实现SPWM、正弦波模拟信号等
qt5.13测试程软件,下面是源码
下图为一个正弦曲线周期
下图为一个正弦曲线周期的1/4部分
//SinCurve.h
#ifndef SINCURVE_H
#define SINCURVE_H
#include <QObject>
#define D_SIN_CURVE_BITS 16
struct SinCurve
{
public:
/**
* @brief SinCurve
* @param D_BITS
* @param size 2的次方
*/
SinCurve(uint16_t size );
/**
* @brief CurveValue
* @param index 取出曲线中的值
* @return
*/
uint16_t CurveValue( int index );
uint16_t angleCurveValue( double angle );
inline int tableSize(){return s_table_size;}
inline uint16_t* table(){return s_table;}
inline int indexSize(){return s_table_size<<2;}
private:
/**
* @brief baseCurveValue
* @param type 曲线类型
* @param index 取出曲线中的值
* @return
*/
uint16_t baseCurveValue( int type, int index );
public:
/*
* 整形数的连续位乘除均采用左移和右移,单片机可以单周期完成。
如: x>>1==x/2; x>>2==x/4; x>>3==x/8
*/
uint16_t D_BITS; // 数组的位宽
uint16_t D_BITS_MARK ; //
uint16_t s_table_size; // 4分之1周期数组长度
uint16_t sh_table_size; // 半周期数组长度
uint16_t *s_table;//;
uint16_t sbit_size; // 1周期精度
uint16_t hbit_size; // 半周期
uint16_t hmod; // 半周期
private:
/**
* @brief createrCurveTable 生成一个正弦周期的1/4正弦曲线数据
* @param size 一维数组大小
* @param s_table 数组指针
*/
void createrCurveTable( int size, uint16_t *s_table );
};
#endif // SINCURVE_H
//SinCurve.cpp
#include "SinCurve.h"
#include <math.h>
#include <qdebug.h>
SinCurve::SinCurve( uint16_t size )
{
this->D_BITS = D_SIN_CURVE_BITS; // 数组的位宽,最大16
D_BITS_MARK = ((0x01<<D_SIN_CURVE_BITS)-1); //
sbit_size=size+2;//1个周期的精度
s_table_size = (uint16_t)powl(2,size); // 4分之1周期数组长度,长度越大曲线精度越高
sh_table_size=s_table_size<<1; // 半周期数组长度
s_table = new uint16_t[s_table_size] ; // 创建保存空间
hbit_size=sbit_size-1;
hmod=((0x01<<(hbit_size))-1);
// qDebug()<<D_BITS<<D_BITS_MARK<<s_table_size;
createrCurveTable( s_table_size, s_table ); //生成数据
// // 1个正弦
// for ( int ik=0 ; ik<2; ik++)
// {
// for ( int i=0 ; i<sh_table_size; i++)
// {
// baseCurveValue( ik&0x01, i%(sh_table_size) );
// }
// }
// // 10个正弦
// for ( int ik=0 ; ik<20; ik++)
// {
// for ( int i=0 ; i<sh_table_size; i++)
// {
// baseCurveValue( ik&0x01, i%(sh_table_size) );
// }
// }
}
/**
* @brief createrCurveTable 生成一个正弦周期的1/4正弦曲线数据
* @param size 一维数组大小
* @param s_table 数组指针
*/
void SinCurve::createrCurveTable( int size, uint16_t *s_table )
{
for(int i=0;i<size;i++)
{
// qDebug()<<i<<D_BITS_MARK-(( sin(i*(M_PI/((size<<1)-1.0))+(M_PI/2.0)) +1)*(D_BITS_MARK>>1));
s_table[i] = D_BITS_MARK-(( sin(i*(M_PI/((size<<1)-1.0))+(M_PI/2.0)) +1)*(D_BITS_MARK>>1));
}
}
uint16_t SinCurve::CurveValue( int index )
{
// int max=sh_table_size;
// int mm=max-1;
//int ik=index/max ;
//int i=index%max ;
int ik=index>>(hbit_size) ;//商
int i=index&hmod ;//余数
// qDebug()<< Curve->baseCurveValue( ik&0x01, i%(Curve->size()*2) );
return baseCurveValue( ik&0x01, i );
}
uint16_t SinCurve::angleCurveValue( double angle )
{
int i = indexSize()*angle/360.0 ;
return CurveValue( i );
}
/**
* @brief baseCurveValue
* @param type 曲线类型
* @param index 取出曲线中的值
* @return
*/
uint16_t SinCurve::baseCurveValue( int type, int index )
{
#if 0
if(type==0)// 加速
{
return s_table[index];
}
else// 减速
{
return D_BITS_MARK-s_table[index];
}
#else
// 4个像限
if(type==0)//
{
if(index<s_table_size)//0-126
{
//qDebug()<<index;
return s_table[index];
}
else if(index<(sh_table_size))
{
//qDebug()<<((sh_table_size)-1-index)<<index;
return D_BITS_MARK-s_table[(sh_table_size)-1-index];
}
}
else if(type==1)//
{
if(index<s_table_size)
{
return D_BITS_MARK-s_table[index];
}
else if(index<(sh_table_size))
{
return s_table[(sh_table_size)-1-index];
}
}
else if(type==2)//
{
if(index<s_table_size)//0-127
{
return (D_BITS_MARK>>1)-s_table[s_table_size-index-1];
}
else if(index<(sh_table_size))//128-255//
{
return (D_BITS_MARK>>1)-s_table[ -s_table_size+index ];
}
}
else
{
if(index<s_table_size)
{
return s_table[s_table_size-index-1];
}
else if(index<(sh_table_size))
{
return s_table[ -s_table_size+index ];
}
}
#endif
}
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "SinCurve.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
private:
Ui::MainWindow *ui;
SinCurve *Curve;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qdebug.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Curve = nullptr;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString tempStr;
for ( int ik=0 ,k=0; k<ui->spinBox_2->value() && ik<ui->spinBox->value()*Curve->indexSize(); ik++, k++)
{
tempStr+=QString::asprintf("%u\n", Curve->CurveValue( ik ) );
}
ui->plainTextEdit->appendPlainText(tempStr);
}
void MainWindow::on_pushButton_2_clicked()
{
if(Curve!=nullptr)
delete Curve;
Curve = new SinCurve( 6 );
QString tempStr;
uint16_t* temp=Curve->table();
for ( int i=0 ,k=0; k<ui->spinBox_2->value() && i<Curve->tableSize(); i++,k++)
{
tempStr+=QString::asprintf("%u\n", temp[i] );
}
ui->plainTextEdit->appendPlainText(tempStr);
ui->pushButton->setEnabled(true);
ui->pushButton_3->setEnabled(true);
}
void MainWindow::on_pushButton_3_clicked()
{
QString temp;
double angle = Curve->indexSize()*ui->doubleSpinBox_2->value()/360.0 ;
for ( double i = angle ,k=0; k<ui->spinBox_2->value() && i<Curve->indexSize()*ui->spinBox->value()+angle;
i+=ui->doubleSpinBox_3->value(), k++ )
{
temp+=QString::asprintf("%u\n", Curve->CurveValue( i ));
}
ui->plainTextEdit->appendPlainText(temp);
}
void MainWindow::on_pushButton_4_clicked()
{
ui->plainTextEdit->clear();
}
//mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>712</width>
<height>635</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>10</number>
</property>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>生成表</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QPushButton" name="pushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>生成数据</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_2">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
<property name="singleStep">
<double>0.000001000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>递进精度</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_3">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
<property name="singleStep">
<double>0.000001000000000</double>
</property>
<property name="value">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>开始相位</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>周期</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>最大数据量</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_2">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1000</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
<property name="value">
<number>20000</number>
</property>
</widget>
</item>
<item row="1" column="2" rowspan="3">
<widget class="QPushButton" name="pushButton_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>生成相
位数据</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>清空</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>