Here is the main code for the ATMEGA328PB. Note that this is for a xplained board.
The main idea of the code is to allow read and write of the MCU registers over the USART port (which for the xplained board, is a virtual COM port that is accessible over USB). So, you set the serial port program to 9600 baud, 8 bits, no parity, and then to write the PORTB register, you type in something like w37=1 or w37=3 (i.e., decimal 37 is 0x25). Please see the latest ATMEGA328PB datasheet, page 445 for the register map.
#include <avr/io.h>
// For the ATMEGA328PB xplained, 16 MHz is available on the external clock
// So, in the fuses section, LOW.CKDIV8 is unchecked
// LOW.SUT_CKSEL is set to Ext. Clock; Start-up time PWRDWN/RESET: 6 CK/14 CK + 65 ms
#define F_CPU 16000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include "main.h"
// Place to store a string for USART communication
static char temp_string[64];
// Simple routine to output a serial string to the UART
void print_serial(const char * const print_string) {
uint8_t temp = 0;
while (temp < strlen(print_string)) {
if ((UCSR0A & 0x20) == 0) {
// Do nothing
_delay_us(10);
}
else {
// Send a byte
UDR0 = (uint8_t) print_string[temp];
temp = temp + 1;
}
}
// Send ASCII 13 and 10
temp = 0;
while (temp < 2) {
if ((UCSR0A & 0x20) == 0) {
// Do nothing
_delay_us(10);
}
else {
if (temp == 0) {
UDR0 = 13;
}
if (temp == 1) {
UDR0 = 10;
}
temp = temp + 1;
}
}
}
// Place to store the user input
static uint8_t rx_in_buffer[64];
// The count of user input
static uint8_t rx_in_buffer_count = 0;
ISR(USART0_RX_vect) {
// Read the character from the buffer
uint8_t temp = UDR0;
// Put the character in the buffer
rx_in_buffer[rx_in_buffer_count] = temp;
// Increment the count
rx_in_buffer_count = rx_in_buffer_count + 1;
// Count has to be less than 63
if (rx_in_buffer_count > 63) {
rx_in_buffer_count = 63;
}
// If the character is carriage return, process the command
if (temp == 13) {
go_process_command();
}
}
void go_process_command() {
// Print some characters in the buffer
//snprintf(temp_string, 64, "Rx: %d, %d, %d, %d, %d, %d", rx_in_buffer[0], rx_in_buffer[1], rx_in_buffer[2], rx_in_buffer[3], rx_in_buffer[4], rx_in_buffer[5]);
//print_serial(temp_string);
// The read command
if ((rx_in_buffer[0] == 114) || (rx_in_buffer[0] == 82)) { // The read command, r or R, expect decimal, for example, expect r72 to read 0x48, OCR0B
//print_serial("r/R");
// The location of the carriage return
uint8_t ind_13 = 0;
// Find character 13
for (uint8_t ii = 1; ii < 64; ii++) {
if (rx_in_buffer[ii] == 13) {
ind_13 = ii;
break;
}
}
// Where character 13 was found
//snprintf(temp_string, 64, "Char13: %d", ind_13);
//print_serial(temp_string);
// For processing the register address (convert ASCII characters to addr)
uint8_t found_it = 0;
uint16_t addr = 0;
uint16_t pow_10 = 1;
// If ind_13 was found, build up addr
if (ind_13 > 1) {
for (uint8_t ii = (ind_13 - 1); ii > 0; ii--) {
if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) {
addr = addr + (rx_in_buffer[ii] - 48) * pow_10;
pow_10 = pow_10 * 10;
found_it = 1;
}
else { // Unexpected character
found_it = 0;
break;
}
}
}
// Print the address and whether the parsing was as expected
//snprintf(temp_string, 64, "addr: %u, found_it: %d", addr, found_it);
//print_serial(temp_string);
// Print the register value
if (found_it == 1) {
volatile uint8_t * reg_addr = (uint8_t *) addr;
uint8_t temp_value = *reg_addr;
snprintf(temp_string, 64, "Reg: %u (%#x) = %d (%#x)", addr, addr, temp_value, temp_value);
print_serial(temp_string);
}
}
else if ((rx_in_buffer[0] == 119) || (rx_in_buffer[0] == 87)) { // The write command, w or W, for example, expect w72=4
//print_serial("w/W");
// The location of the carriage return
uint8_t ind_13 = 0;
// Find character 13, carriage return
for (uint8_t ii = 1; ii < 64; ii++) {
if (rx_in_buffer[ii] == 13) {
ind_13 = ii;
break;
}
}
// The location of the =
uint8_t ind_eq = 0;
for (uint8_t ii = 1; ii < 64; ii++) {
if (rx_in_buffer[ii] == 61) {
ind_eq = ii;
break;
}
}
// Where character = and 13 were found
//snprintf(temp_string, 64, "Char=: %d, 13: %d", ind_eq, ind_13);
//print_serial(temp_string);
if ((ind_eq > 1) && ((ind_eq + 1) < ind_13)) {
// For processing the register address (convert ASCII characters to addr)
uint8_t found_it = 0;
uint16_t addr = 0;
uint16_t pow_10 = 1;
// Get the register address
for (uint8_t ii = (ind_eq - 1); ii > 0; ii--) {
if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) {
addr = addr + (rx_in_buffer[ii] - 48) * pow_10;
pow_10 = pow_10 * 10;
found_it = 1;
}
else { // Unexpected character
found_it = 0;
break;
}
}
// Print the address and whether the parsing was as expected
//snprintf(temp_string, 64, "addr: %u, found_it: %d", addr, found_it);
//print_serial(temp_string);
// Attempt to set the register value
if (found_it == 1) {
// Print the current value of the register
volatile uint8_t * reg_addr = (uint8_t *) addr;
//snprintf(temp_string, 64, "Reg: %u = %d, old value", addr, *reg_addr);
//print_serial(temp_string);
// Now, parse the value
found_it = 0;
pow_10 = 1;
uint16_t in_val = 0;
// Get the value
for (uint8_t ii = (ind_13 - 1); ii > ind_eq; ii--) {
if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) {
in_val = in_val + (rx_in_buffer[ii] - 48) * pow_10;
pow_10 = pow_10 * 10;
found_it = 1;
}
else { // Unexpected character
found_it = 0;
break;
}
}
// Print the value and whether the parsing was as expected
//snprintf(temp_string, 64, "New value: %d, found_it: %d", in_val, found_it);
//print_serial(temp_string);
if ((found_it == 1) && (in_val <= 255)) {
// Write the value
*reg_addr = (uint8_t) in_val;
snprintf(temp_string, 64, "Reg: %u (%#x) = %d, new value", addr, addr, in_val);
print_serial(temp_string);
}
}
}
}
else {
print_serial("Command error");
}
// Last things to do
// Set the buffer count to 0
rx_in_buffer_count = 0;
// Clear the buffer
for (uint8_t ii = 0; ii < 64; ii++) {
rx_in_buffer[ii] = 0;
}
}
int main(void)
{
// Get the UART ready
UBRR0H = 0; // Oscillator is 16 MHz, 9600 is decimal 103
UBRR0L = 103;
// Enable Rx interrupt, enable Rx, enable Tx
UCSR0B = (1 << 7) | (1 << 4) | (1 << 3); // Enable RXCIE1, Enable Tx and Rx
UCSR0C = (0 << 6) | (0 << 4) | (0 << 3) | (3 << 1); // Asynchronous, No parity, 8 bits
_delay_ms(1);
// Enable interrupts
SREG |= (1 << 7);
// PB5 is the USER_LED, labeled D200 on the ATMEGA328PB xplained board
// PB0 and PB1 for the shutter control
DDRB = (1 << 0) + (1 << 1) + (1 << 5);
PORTB = 0;
// Blink the LED waiting for serial port input
print_serial("Go time!");
while (1)
{
//PORTB &= 255 - (1 << 5);
//_delay_ms(500);
//PORTB |= (1 << 5);
//_delay_ms(500);
_delay_ms(1);
}
}
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.