I have 20 odd years in programming starting from pascal 7 to delphi. I want to start programming micro controllers using C and the tool most electronics kit recommend is winAVR with programmers notebook. I have installed the software and would like to start compiling code and I'm lost to say the least and can't find any simple documentation to get myself onto a track where I can start testing code. Can anyone offer some good starter material?
Whereas for PC's the usual first program is "Hello, World!", in the embedded world (one lacking displays, as least to start with, the equivalent is the blinky led: you attach a LED to some output pin of your processor (don't forget the current-limiting resistor!: you need a resistor in series with the LED), and you make the LED blink. You can find plenty of blinky LEDs for AVR, but we can write one right here:
// The next define tells delay.h what your CPU speed is, assuming 1Mhz
#define F_CPU 1000000UL
#include <util/delay.h>
main() {
while(1) { // loop forever
DDRB = 0xFF; // Set the direction of all pins
// on port B to OUTPUT (can change to some other port)
PORTb = 0xFF; // Set all pins on port B high (can change to some other port)
_delay_ms(1000); // Wait one second;
PORTb = 0x00; // Set all pins on port B low (can change to some other port)
_delay_ms(1000); // Wait one second;
}
}
It should compile on WinAVR, and load correctly. Change PORTB and DDRB to some other port of you'd like. Note that this program changes all the pins on that port: so if your port B has 8 pins, all of them will blink a led hooked up to them. Don't forget the current-limiting resistors, and that LEDs are directional: they only work when plugged in one way, and not the other.
Related
I've been working on a project where I use a PGA2310 volume control IC to set the volume of an audio signal. The chip's interface is supposedly SPI, but no matter how much I try, I just can't seem to get it right. The chip takes a 16 bit word over SPI that contains the left and right channel volume information.
I'm wondering if I am using the sdk all wrong and my code is whacked.
I guess my question is: Am I setting up and using the SPI functions correctly?
Here is my code
/**
* SPI interface for PGA2310 volume control ic
*/
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "pico/time.h"
const int CS = 0;
const int SDI = 1;
const int SCLK = 2;
const int LED_PIN16 = 16;
const int LED_PIN25 = 25;
uint16_t PGA2310();
uint16_t PGA2310() {
int baud = 1600000;
// SPI inistalization
spi_init(spi0, baud);
spi_set_format(spi0, 16, SPI_CPOL_0 , SPI_CPHA_0, SPI_MSB_FIRST);
// Sets SPI pins
gpio_set_function(CS, GPIO_FUNC_SPI);
gpio_set_function(SDI, GPIO_FUNC_SPI);
gpio_set_function(SCLK, GPIO_FUNC_SPI);
// Sets LED pins
gpio_init(LED_PIN16);
gpio_set_dir(LED_PIN16, GPIO_OUT);
gpio_init(LED_PIN25);
gpio_set_dir(LED_PIN25, GPIO_OUT);
// Data to send to chip. only sending first 8 bits for right channel.
// This is because I am currently just testing the output of the right channel
uint16_t high = 255;
uint16_t low = 100;
// Test by toggling between high and low volume states with LED indicators
while (true) {
gpio_put(LED_PIN25, 1);
spi_write16_blocking(spi0, &high, 1);
sleep_ms(2000);
gpio_put(LED_PIN25, 0);
spi_write16_blocking(spi0, &low, 1);
sleep_ms(2000);
}
}
I've tried a bunch of different methods that I found online for using SPI with the pico SDK. I've tried just sending 8 bits.
Let me know if more info is needed.
As explained in comments, SPI normally consists of 4 signals: /SS, SCLK, MOSI and MISO.
/SS = slave select, also known as chip select. Almost always active low.
SCLK = serial clock.
MOSI = Master Output Slave Input. The main data line. Your MCU seems to call this SDO (serial data out?).
MISO = Master Input Slave Output. Optional signal for duplex (two way) communication SPI. Your MCU seems to call this SDI (serial data input).
In this case the MCU is the master so you should be using MOSI/SDO. A MCU is almost always the master, except when communicating with other MCUs.
Additionally, always double check which CPOL and CPHA settings that the slave expects. Getting these wrong is a classic problem and can lead to subtle "clock skew" problems where everything works fine most of the time, then fail and give corrupt data intermittently.
The names you pick for variables/constants in C code do not have any effect on the hardware and they disappear as soon as the code is compiled. The most important thing is that you understand how the hardware works, read the documentation for the RP2040 SDK functions you are calling, and then pass the correct values to the RP2040 SDK functions.
The biggest problem is that you need to rethink every pin assignment. The RP2040 hardware SPI pin functions are defined in column F1 of the "GPIO Functions" section of the RP2040 datasheet. Here is an excerpt from that table:
This table tells us, for example, you cannot use pin 0 as the SPI0 CS function. If you assign that pin to be an SPI pin, it will be the SPI0 RX (data receiving) pin.
At a minimum, you need to pick one pin to be the SPI0 SCK pin and another to be the SPI0 TX pin, and you must connect those pins from the RP2040 to the equivalent pins on your device. Then you might also need to pick an RP2040 pin to control the CS pin on your device, if it has one. On the RP2040 side, this pin would be configured as a GPIO output pin and you would drive it low or high to enable your device. Refer to your device's datasheet for details about what signals it expects on its inputs and then use an oscilloscope to make sure you are generating compliant signals.
Another problem is that the spi_write16_blocking is probably modifying your high and low variables, so you will probably need to set those to the right values before each time that you use them. (So there is no point in having two different variables like that, just have one.)
I have microprocessor at32uc3b0256 and I want turn on leds, (simple program from examples). To do this I use Atmel Studio. I found sample code:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRC = 0xFF; //Makes PORTC as Output
while(1) //infinite loop
{
PORTC = 0xFF; //Turns ON All LEDs
_delay_ms(1000); //1 second delay
PORTC= 0x00; //Turns OFF All LEDs
_delay_ms(1000); //1 second delay
}
}
But when i wrote it to Atmel Studio i got some errors, Atmel Studio dont see DDRC and PORTs as variable. How can I fix it?
Screen form Atmel Studio
You are using GPIO example for AVR8 architecture. AVR32 architecture is completely different introducing GPIO module as separate HW block connected through PBA (I think). There are no registers like DDRC,...
You can look at AVR32 architecture as on network of subcomponents where MCU core is only one of the modules. There are 2 main buses PBA and PBB each connected to different modules.
To make AVR32 firmware work you need do this:
configure and start main MCU core clock you want to use
AVR32 MCU core is usually running at low 32KHz clock after reset. To achieve better performance you need higher clock up to 66MHz. I usually start PLL at some common frequency and divide all clocks (CPU,PBA,PBB,HSB) from it later. As a source for the PLL you need some clock for example internal RC or oscillator driven by external crystal. If you want also USB then you need to take in mind it needs specific frequency so compromise ... For more info check SCIF module in datasheet and or in examples.
switch to it when started properly
Either wait a bit (100ms) or check if clock is running directly (SCIF module has some capabilities for it I think).
configure/start used HW modules
now do your stuff
Bootlaoder
Another thing you need to take care of is the boot loader. I do not like JTAG as I have a bad experience with it (does not take much to fry it and the programing with it is really uncomfortable). With JTAG you can easily wipe out bootloader (each chip is shipped with it) and trust me getting it back to work is really nasty.
Bootloader on the other hand is simple and elegant. For example I use FLIP and has simple comandline file for programing chip. Then I just open command prompt execute it. And on each rebuild/programming I just hit up arrow to repeat last command in the prompt and hit enter. In comparison to many clicks with JTAG is this much faster and simpler. Here example of the cmd:
avr32-objcopy -O ihex AT32UC3L064.elf AT32UC3L064.hex
Batchisp -device AT32UC3L064 -hardware RS232 -port COM1 -baudrate 115200 -operation onfail abort memory flash erase f blankcheck loadbuffer AT32UC3L064.hex program start reset 0
The avr32-objcopy.exe is in the AVR studio bin directory.
With Bootloader you need to tell the compiler your program is not starting at 0x0000 because that would be overlapping with bootloader. To do that see the trampoline examples.
This is how my AVR32 app usually looks like:
#include <avr32/io.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "intc.c"
#include "gpio.c"
#include "pm_uc3l.c"
#include "scif_uc3l.c"
#include "adcifb.c"
#include "flashcdw.c"
#include "pdca.c"
//#include "pwma.c"
#include "tc.c"
#include "usart.c"
#include "eic.c"
#include "genclk.h"
#include "osc.c"
#include "dfll.c"
#include "sysclk.c"
#include "status_codes.h"
#include "cycle_counter.h"
#include "sleep.h"
#include "delay.c"
#define cpu_clk 30000000
#define _LED AVR32_PIN_PA04
void system_init()
{
delay_init(115000);
Disable_global_interrupt();
INTC_init_interrupts();
scif_start_rc120M();
delay_ms(100);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_CPU,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBA,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBB,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_HSB,PM_CKSEL_DIVRATIO_4);
pm_set_all_cksel(SCIF_RC120M_FREQ_HZ,cpu_clk,cpu_clk,cpu_clk);
flashcdw_set_flash_waitstate_and_readmode(cpu_clk);
pm_set_mclk_source(PM_CLK_SRC_RC120M);
delay_init(cpu_clk);
}
//------------------------------------------------------------------------------------------------
void wait_ms(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999)/1000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
void wait_us(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999999)/1000000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
int main(void)
{
system_init();
// here init what you need
gpio_configure_pin(_LED,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
for (;;)
{
// here do your stuff
gpio_tgl_gpio_pin(_LED);
wait_ms(200);
}
//------------------------------------------------------------------------------------------------
I do not use framework manager instead I include the stuff myself... and my framework is rewritten to avoid unnecessary includes and slowdowns of compilation. Also beware that framework updates are not always compatible so sometimes after update your code will not compile ... It is better to have one solid framework and not update it unless you really need to.
Select only the modules you need to (no need to include them all). For example you need intc,gpio,scif etc my includes are from bigger project so many of them are useless for you and also not all headers/modules are available for all of the AVR32 chips.
I got a bit off topic (I think was necessary) so back to GPIO
The API and architecture is completely changed. Do not be fooled by the pin names. For example pin PA35 does not mean port A pin 35 !!! There is no port PA It is just naming convention without any real meaning to the architecture which is a bit silly and took me a while to got along with it. There are as many ports as needed to cover all the pins. Each port support 32 pins and the pin number is the real thing you need to know.
Each pin is defined somewhere in avr32/io.h as a define like AVR32_PIN_PA04 and it contains numerical value of the pin position in chips GPIO. To obtain gpio port/mask you just do this:
port = pin>>5
mask = 1<<(pin&31)
Now to access GPIO registers directly I recommend to look at gpio.c. You can set,res,test,read 32 pins at a time to speed up (if they are at the same port). The speed is dependent mainly on the buss clock (usually PBA for GPIO) so if your clock for it is low do not expect high toggle rate. beware GPIO access is slow and if not used wisely can kill the performance of your code...
If HW pins selected for your App are done wisely you can have really fast speeds. For example I got toggle speeds around 2-5 MHz !!!
Here example of setting a pin from gpio.c
void gpio_set_gpio_pin(uint32_t pin)
{
U32 bit= 1 << (pin & 0x1F);
volatile avr32_gpio_port_t *gpio_port = &GPIO.port[pin >> 5];
gpio_port->ovrs = bit; // Value to be driven on the I/O line: 1.
gpio_port->oders = bit; // The GPIO output driver is enabled for that pin.
gpio_port->gpers = bit; // The GPIO module controls that pin.
}
You can use this to set multiple pins at the same port simply by exchanging bit with the mask of all pins you want to set ...
If you are using Interrupts for GPIO beware that the interrupt controller INTC is also a separate module connected by buss and wrongly set clock or wait states can cause huge problems.
Afternoon all,
I am currently delving into the brand new world (to me anyway) of embedded systems and am struggling to understand something. I've looked around for an answer but either the answer is so staggeringly obvious that it's not implicitly stated or I am asking the wrong question.
The question is this; I have a QL200 development board which has several components I am interfacing with a PIC16F877A (Push buttons, LEDs, LCD screen and buzzer). The last component I am really struggling with is the buzzer.
Through some reading , I am led to believe that to make the buzzer sound I simply have to set the pin it is operating on high. However I am unsure how to do this. Furthermore, I have found (by luck or guidance) the ports that all the other components run on but I have no clue as to actually how they are assigned their ports. Is it by assigning them a port or are they set on a certain port as standard?
For example, my LCD panel is running off PORTD:
#define lcd PORTD
void writeCommand(unsigned char ch)
{
lcd = ch;
RS = 0;
RW =0;
E = 1;
lcdDelay();
E=0;
}
void Init_lcd(void)
{
ADCON1 = 0x07; //required setting of analog to digital
TRISD = 0x00;
TRISA1 = 0;
TRISA2 = 0;
TRISA3 = 0;
writeCommand(0x0f);
writeCommand(0x38); //set to two line mode
clearDisplay();
writeString("MAIN MENU");
}
Is that from a data sheet? I simply got told it was on PORTD so ran with that and it works.
However now it comes the turn of the buzzer and I'm stumped as to even get started. Several examples online use PORTB but I'm already using push buttons as inputs on PORTB:
#define TempButton1 RB1
#define TempButton2 RB2
#define TempButton3 RB3
Last thing, is that once I find the port the buzzer is running on, is it a simple matter of raising it high to get the buzzer to sound? i.e:
//declarations
#define buzzer PORT(x)
//in a function somewhere
buzzer = 1; //hopefully buzzer should sound
A lot of my research indicates that this way should work but some use PMW and frequencies to achieve a sound. Thanks in advance!
You will have to toggle the output port pin at twice the frequency you desire, since this is also described as an audio and voice feature, and just enabling the output cannot do that. If it shares a port with other outputs, you must preserve the state of the other outputs while you toggle it.
If you don't have an oscilloscpe, get one if you are doing any serious work. Also useful for seeing port levels (in or out) at the chip.
I built this motor shield based on the L298N chip to control two motors of a tank. It uses pins 5 and 6 for one motor, and pins 10 and 11 for the other.
While trying to add a TSOP 4838 in order to control the tank with an IR remote I noticed that moving the motor on pins 10/11 in reverse only works at full speed - that is, a HIGH (255) value on pin 11. Anything below that value doesn't output anything on pin 11 (measured voltage on those pins is 0 V).
For the remote I use this library. The IR receiver is connected on pin 2 (but the pin doesn't matter). The problem is the library code itself. The line that enables IR listening irrecv.enableIRIn(); is what is causing the problem. I learned that there is a conflict of internal Arduino timers and the pins used for PWM by the shield.
This is the code to power the motor in reverse:
#include <IRremote.h>
// IR receiver configuration
const int irPin = 2;
IRrecv irrecv(irPin);
// Motors configuration
const int mLeftPin1 = 10;
const int mLeftPin2 = 11;
const int mRightPin1 = 5;
const int mRightPin2 = 6;
void setup()
{
// Start IR
irrecv.enableIRIn();
// Setup motors
pinMode(mLeftPin1, OUTPUT);
pinMode(mLeftPin2, OUTPUT);
pinMode(mRightPin1, OUTPUT);
pinMode(mRightPin2, OUTPUT);
// Move left motor in reverse, slower speed
analogWrite(mLeftPin2, 100); // This works only with 255 instead of 100
digitalWrite(mLeftPin1, LOW);
}
Now, I found here that the pins used by the timers on Arduino Uno are:
Pins 5 and 6: controlled by Timer0
Pins 9 and 10: controlled by Timer1
Pins 11 and 3: controlled by Timer2
So my questions are:
Why does the shield in the instructable use pins 10 and 11 for PWM ? They correspond to 2 different timers. Why not 9 and 10?
In order to use the IR along with the motor shield, what timer should I configure the IR library to use?
If the answer is 2, a line should be uncommented in IRremoteInt.h. I am guessing the Uno would take the else branch at line 68, although only timer1 and timer2 are there. I wonder why timer0 couldn't be used for the Uno.
Although I'd like to leave cutting traces and resoldering as a last option, another possibility would be to change the pins used by the shield, but which? And I am guessing this would also be paired with configuring the timers to PWM on other pins than default, but I don't know anything about timers/interrupts and my knowledge of Arduino and C is limited.
I made this a long question, because I want to learn not just solve the problem, so feel free to explain more than what is asked.
While looking up for a solution I also found other conflicts to keep in mind when using PWM or timers:
Timer0 is an 8-bit timer, it can hold a maximum value of 255. It is used by delay() and millis(), so there are consequences when messing with it
Timer1 is a 16-bit timer, it can hold a maximum of 65535 (an unsigned 16-bit integer). The Arduino Servo library uses this timer
Timer2 is an 8-bit timer used by the Arduino tone() function
And, of course, the IRremote library uses TIMER_RESET, so depending on which timer it uses it can conflict with the associated pins.
Not all hardware is designed in the best way. Using 10 and 11 is indeed wasteful because it requires two timers.
2/3. Ideally you will use a timer that is not Timer0. Here's some more details on timers/interrupts:
The Arduino chip (328P) has three timers. Each timer can be used for multiple uses, however it is important to note that you can only have one timer interrupt enabled for each timer.
Take Timer0 for example. It interrupts in order to generate the proper delays for the delay() and delay_us() methods. It also is used for the PWM outputs on pins 5 and 6. This can happen because the PWM outputs don't use a timer interrupt, they use separate output compare modules.
Now looking specifically at your problem, it should work fine, even though you have a PWM output using timer2, the PWM does not take an interrupt on timer2 so the IR library should be free to use that interrupt. However, looking into the IR library code, we see this piece of code:
ISR(TIMER_INTR_NAME)
{
TIMER_RESET;
It appears that every time it interrupts, it resets the timer count. This could be why your PWM output is not working properly. The output compare module is waiting for a certain tick count, and it never reaches that.
As to why it somehow works at 255, we can take a look at the analogWrite code:
void analogWrite(uint8_t pin, int val)
{
// We need to make sure the PWM output is enabled for those pins
// that support it, as we turn it off when digitally reading or
// writing with them. Also, make sure the pin is in output mode
// for consistenty with Wiring, which doesn't require a pinMode
// call for the analog output pins.
pinMode(pin, OUTPUT);
if (val == 0)
{
digitalWrite(pin, LOW);
}
else if (val == 255)
{
digitalWrite(pin, HIGH);
}
So by writing 255, the analogWrite code ignores the whole PWM and output compare thing, and just writes the pin high.
Finally, as to solving your problem, I would personally go the route of not using pins 11 and 3 (timer2). Yes it will require a small rewiring, but that way you can free up timer2 for the IR library to use.
Alternatively, you could poke around the IR library and try to make it work without resetting the count.
Pay attention to the board used, if you use Arduino Uno, then the code responsible would be: // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
else
//define IR_USE_TIMER1 // tx = pin 9
define IR_USE_TIMER2 // tx = pin 3
endif
I had the same problem with a prebuilt L298 V2 motor shield.
The pins were marked like this on the shield:
Motor1: pin 3 and 5
Motor2: pin 6 and 9
I use PIN10 instead of 3 and using a small workaround: I put a wire from PIN10 to PIN3 on the SHIELD.
My project was to control my robot with a SAMSUNG TV remote control.
I knew there is a similar post:
Steps to make a LED blink from a C/C++ program?
But now I am working on a arm-based development board, and it seems to have two serial ports that I could use it to make a LED on or off.
Basically I think the flow is , make one pin in serial "1" or on and the LED will be turned on and "0" to make it off.
Is there some reference code in C-language I could refers?
Generally speaking, the board should come with some Board Support Package (BSP) which lets you control the built in I/O. Look for a serial library if you really want to use the Hardware flow control signals.
I'd recommend looking for some GPIO (General Purpose I/O, or digial I/O) on the board, which typically lets you configure it as an input or an output. You should be able to connect the LED via a current limiting resister between a digital I/O line and a ground pin. Make sure you have the LED oriented correctly if you connect it backwards it will block the current instead lighting. And as always make sure you check it out with a digital voltage meter before connecting it.
Even if you don't have a BSP for digital I/O the configuration is usually pretty simple.
Set a bit in a register to enable it, set bit in another register to select input or output they will normally be arranged in 8-bit "ports." Some systems allow you configure individual I/O pins, other will only allow you to configure the whole port for input or output. Then you just write a 1 or 0 to the bit you want to control in an write/output register.
ARM chips typically have a considerable amount of built in peripherals today, so most boards will just be bringing the I/O out to physical connectors on the board and you may need to read the chip vender's documentation to find the register memory map. Better board venders will supply documentation, a library (BSP) and examples. Luminary Micro even supplies chips with built in ethernet MACs and PHYs, just add a connector and Magnetics and you have a 1 chip Webserver.
This will, I'm afraid, be heavily dependent on the specifications of the particular arm-based development board you are using.
You need to find documentation specific to that board.
I used to do this kind of programming before.
You need to study the serial port connection
http://www.lammertbies.nl/comm/cable/RS-232.html
http://www.beyondlogic.org/serial/serial.htm
It has +5v, -5v on the output, I can't remember clearly now. Not every pin is needed.
I never use ARM before, but I use a 8-bit PIC controller to program it. I guess you can find a lot of example online.
The preferred alternative for controlling a GPIO is via a BSP. Because this BSP (board support package) does all the work for you in setting all peripherals to good defaults and and allowing you to call a function. Possibly your BSP of choice will have a function to write a byte to an 8-bit GPIO port; your LED will only have one bit. In this case your C code could look like: (at least: it will work like this on Luminary Micro kits). (Example code; requires a bit of extra work to make it compile especially on your kit).
/* each LED is addressed by an address (byte) and a bit-within-this-byte */
struct {
address, // address of IO register for LED port
bit // bit of LED
} LEDConfigPair;
struct LEDConfigPair LEDConfig[NUMBER_OF_LEDS] = {
{GPIO_PORTB_BASE,0}, // LED_0 is at port B0
{GPIO_PORTB_BASE,1} // LED_1 is at port B1
} ;
/* function LED_init configures the GPIOs where LEDs are connected as output */
led_init(void)
{
U32 i;
for(i=0;i<NUMBER_OF_LEDS;i++)
{
GPIODirModeSet( LEDConfig[i][0], LEDConfig[i][1], GPIO_DIR_MODE_OUT );
}
}
/* my LED function
set_led_state makes use of the BSP of Luminary Micro to access a GPIO function
Implementation: this BSP requires setting 8 port wide IO, so the function will calculate a mask (
*/
set_led_state(U8 led,bool state)
{
U8 andmask;
U8 setmask;
andmask = ~(1 << LEDConfig[led].bit);// a bitmask with all 1's except bit of LED
if (true == state)
{
setmask = (1 << LEDConfig[led].bit); // set bit for LED
} else
{
setmask = 0;
}
GPIOPinWrite(LEDConfig[led].address, andmask, setmask);
}
Of course this is all spelled out; it can be done in a single lines like this:
#DEFINE SETLEDSTATE(led,state) GPIOPinWrite(LEDConfig[led].address, ~(1<<LEDConfig[led].bit),(state<<LEDConfig[led].bit))
this will do the same, but only makes sense when you can dream bit masks, and you only want to toggle some LEDs to debug the real program...
The alternative: bare metal.
In this case you need to set up everything for yourself. For an embedded system, you need to be aware of pin multiplexing and power management (assuming memory controller and cpu clocks are already set up!)
initialization: set pin multiplexing in such a way that the function you want to control is actually mapped on the package.
initialization of pheripheral (in this case either a UART, or a GPIO function on the same pin)
You can't do it using Rx or Tx pins of Serial port. For that you just need to control the RTS or CTS pins of serial port.
Just google for "access COM port in VC++ code" and then control the RTS and CTS status pins to turn ON and OFF any external device.