Florian's most newest Diary

ふろりあんの再最新日記

オシレータの音量調節ができるようになった

[main.cpp]

#include "mbed.h"
#define MAIN
#include "global.h"

#define ADD 0x2000000
/*#define ADD 0x20000*/

/*static unsigned int gLEDOn=0x0;*/
static Channel* gChannel[2];

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
//static void tick();

int main() {
    gChannel[0]=new Channel(INTERRUPT_TIME_US);
    gChannel[0]->setOmega(ADD);
    gChannel[1]=new Channel(INTERRUPT_TIME_US);
    gChannel[1]->setOmega(ADD+0x100000);
    int volume=0x1000;
    while(1) {
        wait(0.1);
        gChannel[1]->setVolume(volume);
        gChannel[0]->setVolume(volume);
        volume-=0x100;
        if (volume < 0)
        {
            volume=0x1000;
        }
    }
}

[global.h]

#define INTERRUPT_TIME_US 22

#include "Channel.h"

extern DigitalOut myled1;
extern DigitalOut myled2;
extern DigitalOut myled3;
extern DigitalOut myled4;

[Channel.h]

#ifndef _CHANNEL_H_INCL
#define _CHANNEL_H_INCL

#define CHANNEL_PART_NUM 16

class Channel
{
    public:
    /**
    * Constructor(only)
    * to construct after mbed has started.
    * this constructor handles interval timer automatically.
    * @value interrupt_us interrupt span (micro second). it work at first time only.
    */
        Channel(long interrupt_us);

        /**
        * Destructor
        * this destructor anatach the interval timer automatically.
        */
        ~Channel();

        /**
        * Set angle speed(0x100000000 per 1 round)
        * frequency is depend on interrupt_us
        */
        void setOmega(long speed);

        /**
        * Set volume(0x10000 max volume)
        * @param volume
        */
        void setVolume(int volume);

        /**
        * advance the Angle and caliculate value this span.
        * it was called by automatically from interval timer.
        * @return value on this tick(max 0xffff0000)
        */
        virtual unsigned long tick();

        long m_Angle;
        long m_Omega;
        int m_Volume;
};
#endif

[Channel.cpp]

#include "mbed.h"
#include "global.h"
#include "Channel.h"

static long interrupt_us;
static int part_num=0;
static Channel* part[CHANNEL_PART_NUM];
static Ticker sTicker;
static long total_value_in_this_span;
static AnalogOut sAnalogOut(p18);

/* interrupt handler */
/*static void tick(uint32_t id);*/
static void tick();

Channel::Channel(long interrupt_us)
{
    myled1=1;
    ::interrupt_us=interrupt_us;
    if(part_num==0)
    {
        sTicker.attach_us(::tick,interrupt_us);
    }
    part_num++;
    for(int i=0;i<CHANNEL_PART_NUM;i++)
    {
        if(part[i]==NULL)
        {
            part[i]=this;
            break;
        }
    }

    m_Volume=0x10000;
}

Channel::~Channel()
{
    part_num--;
    for(int i=0;i<CHANNEL_PART_NUM;i++)
    {
        if(part[i]==this)
        {
            part[i]=NULL;
            break;
        }
    }
    if(part_num<=0)
    {
        sTicker.detach();
    }
}

void Channel::setOmega(long speed)
{
    m_Omega=speed;
    myled2=1;
}

void Channel::setVolume(int volume)
{
    m_Volume=volume;
}

unsigned long Channel::tick()
{
    m_Angle+=m_Omega;
    if (m_Angle & 0x80000000)
    {
       myled3 = 1;
        return (0xffff*m_Volume) >> 16;
    }
    else
    {
        myled3 = 0;
        return 0;
    }    
}

void ::tick()
{
    long long value=0;

    for (int i=0;i<CHANNEL_PART_NUM;i++)
    {
        if (part[i]!=NULL)
        {
            value+=total_value_in_this_span + part[i]->tick();
        }
    }
    value = value>=0x10000 ? 0xffff : value;
    sAnalogOut.write_u16(value);
    myled4=value > 0x80000000;
}

肝はAnalogOut#write_u16()。今まで=で電圧を与えてたんだけど、=はfloatでの電圧値だったみたい。32bitの上位10bitが有効って、どこで見た情報やら。write_u16で16bitの上位10bitを取るようにした。

仕方なく掛け算は使ってるけど割り算はシフト、まあ1tickにトラック分の掛け算くらいなら大丈夫だろう。